Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.0/patches/2175216/?format=api
{ "id": 2175216, "url": "http://patchwork.ozlabs.org/api/1.0/patches/2175216/?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-26-den@valinux.co.jp>", "date": "2025-12-17T15:15:59", "name": "[RFC,v3,25/35] NTB: hw: Introduce DesignWare eDMA helper", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "b49566be82e3c91094326ed48ccd9eb6b21164e0", "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-26-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/2175216/checks/", "tags": {}, "headers": { "Return-Path": "\n <linux-pci+bounces-43192-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=Vrppv7b9;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-pci+bounces-43192-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=\"Vrppv7b9\"", "smtp.subspace.kernel.org;\n arc=fail smtp.client-ip=52.101.229.13", "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 sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4dWdJP2GRCz1xty\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 18 Dec 2025 02:39:17 +1100 (AEDT)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 57A9B30EA639\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 17 Dec 2025 15:35:40 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 4D292361DDB;\n\tWed, 17 Dec 2025 15:17:49 +0000 (UTC)", "from TY3P286CU002.outbound.protection.outlook.com\n (mail-japaneastazon11010013.outbound.protection.outlook.com [52.101.229.13])\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 A885935E55A;\n\tWed, 17 Dec 2025 15:17:46 +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:36 +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:36 +0000" ], "ARC-Seal": [ "i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1765984669; cv=fail;\n b=c28jkWNWEmzJ6AQMxDK5TT5RW5WApEelZp7VN8H2Nr03T8ndnnx6tdXBbeexUVeQ5ECxSJfBC8S6FpBvV/fNceieklJnQw48JXpPfNC+eAKGpY/Ksuqp8v1rxplC3x8NLReeMI8VqprGtRE3up8s/7ky6FiA/uxI6kGKh9QQQ24=", "i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n b=Rdsn95x3hV+v9H5iJbEdARDHCDj98oNtEcSa1PwPC6J5PxAgKAueF2RJrL+yCqV++XOlwK0X94p1mdJfdbs1QAthL+wOJ9hMyk6rnCo9tBmgHhfjQM8VLpDkAJNbXtkF5fBD8WezmppHvk6ak4BlyKJ30TC91wUXxVrumkqaj/7m5yewGUpbJL/kBfovrRdJERFaNiagp8YCSBu/5s9j949f2didgXFJTglT7B2DIYLmtOZtDtjRiIeJZQyIz9dLKI7b82pZ8km2Fli8TCZHIp5uaRE5m6zf3E68d1VugZNLjFZlMuUB/AC4I3NCPGBVCJ5e8kt0Iom9QvDCFNwowQ==" ], "ARC-Message-Signature": [ "i=2; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1765984669; c=relaxed/simple;\n\tbh=d0rACje9YjjOsG5lQZ7JZ5/XwL3Df1IiGPbPtd6KSxo=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t Content-Type:MIME-Version;\n b=Z6UVd5lypjRxSgQUGXWLXBW7QG7m/iVzPeqKDgPARt8h++H4xa3RQVMwCXZhKPBCLpUh3zy2MeFaC8/mdtOBozRIv35ESIwfLSDQGGW85tDV4NJAZ1lvnJyo3mIHELDm4JKDsGgjFxMOabhLaS/yN1NsYYNUktWQXUt3CMWIj+0=", "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=rL83BuiDgQhlPZrb1PXPTF4fyQ31mx307j1bQxvQqP0=;\n b=rciSIdAmy75kgmxAMnnTl3xthyJf9Ho7GNtjhS76Gu4nVKxJmDIJfR/UhSSXKs+k6+i18rxWu4WJBKI3fHqm2AnXafU4QE6YYi0nNTwkxf0QFIZfYHfI8P5qc2ttzGBELY0sc/rIqjAO82VCu9tTTIyvBHkQgx+fzXDab3Q5Px2gyeq4BC8Qj/zHToKsHochrIwlaUo+H4ZYfCfaH2L9PvcbwJu6n+v2R7f6LmCptQhRuxKCg+KRvTVDzGQRD2bHOP9OpNfmsk9GxEC098E3yprhs1ltEDgjAh49fAOQR0Zq/laRe9+c2M+Rr9LKkXPsjLewsVCCkLf8bxIq5v8U2g==" ], "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=Vrppv7b9; arc=fail smtp.client-ip=52.101.229.13", "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=rL83BuiDgQhlPZrb1PXPTF4fyQ31mx307j1bQxvQqP0=;\n b=Vrppv7b9Lqm5f8bZU//HIiHyITcIPLxKTjf7jYHrwB4duz88iWmZthiwHTKGznEcADoA16BW18tOdfKYa5S4t5mRJac2l04BkEmvPDJ3CfPUzMCQ+9QWkkDIQAThSU3LZVm61t+CSScsA3HMiaOKPgw+EI284axn2nHqpEa9goI=", "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 25/35] NTB: hw: Introduce DesignWare eDMA helper", "Date": "Thu, 18 Dec 2025 00:15:59 +0900", "Message-ID": "<20251217151609.3162665-26-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": "TY4P286CA0088.JPNP286.PROD.OUTLOOK.COM\n (2603:1096:405:369::19) 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": "1f9fab2d-e9a2-4516-cdf9-08de3d7f4521", "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 LhFmzEObNAFdIJTiUV+FiPJogMkZKZKugFDf5JC06L/IO8opSVDVWQUdFoQb/snk3vrFRMIWxGBxEj3D+1VHmSMnDUT8jZFeXLr9WACzS8iQzOlzANrZmqEo/pxW824+zDDVRY0Z6jTIsZk63ft5ZfyXUJ5+FNHnQaIfsbAmafemaCmOIR4hIi5plO8hqr4IARssVMNr7HZlp2hHnz0lre+i5yXB5qZ2AAUHwO3q11PEC55xw8CBqeq0VK/SLqGy4Mw0+yY/MuJTQ8BRIvx3XYkuLlpC9mJugurzoPrbiSdUXmSYiIYJrK0vsCa9Pxh7pt7SRF5gL5NlQ8rm8+tZXJeH2cNwERAadG4QDJkPAe4OSTt8cSARBpuF9kJKOR0wzEJQ/I8ZLQl6OQfifIvECYajv2JSXzVgvWaAyadsDN7mECNnDXgGPmAU4mLsXu3+re2pWb4xdcD8yFix3XXKJe04Utugb+4rRF9mrZsub7x2f9qn/DH2VM7LZSDwhY9uIdcTV/j151kOw8t0DosSoI1pioVbC2pDBMYWRqqn4wR3ICp5/xF72/e2pdV4qPA+P2XwMQL49AEz4aPAcLxkRRQuTB4hbJ+jqaaUcbYHxPXPQp57bmq6iZpe+0gUEcwkFAjweDoRPo7mxk+wTjeSfu3uY1pqOkMXPRBkJmfmITasaZiWCfqeRbY1+oWdoTCQLphvUcThtKEOfT0cjFkZbZhqfgtoSMy4ZUlmPQE80OImMaAh/ca//oGfoR1+GOVbNNR+gTWzrt0IL1D5OsbCJZ/WmlsanqCt7h2SZrNoH6jKKCII0+lipiZqMgCetTF/QHqSU80uPza7EFMqJ4Bvg4HJpc2zf1G32BB+7Ff/eMtG8yTWNZ206txYjaSplCRFvWZWQmhANSzbonmZWJ4YLNYTo9LEkpDTnn7LYqOlpkExxY93qKzDsAAB2Zsfp2DisHH1pNoBDFPkUbitpr0VYmFvnWjxRpum4uACfGBzbUmSapZPC+zh2wzfZqufZD2NgdrQSnkAbJCZzuuBgVYPZYdgjYwcdWDtiMQNu0lv3NI5UDqDUQApGMiDZ7z/HIe0TI/FwKqLRvbpEd+Iu9tO01aAJor2IHAhIuJZmUIaIjN6Ob8ANAs8/FKFaqSIlhtM6czwq/ehVs16qa7WxLC+KWQ+ux5W1bXLE/00FgnC9nTh0cUx+0PWaq93Zf3Rg0UOsw3KbkevZ3AVJaPd/mW8img0gwkIhv1QbyrCytc6pyIZfLfHX2ihLvw5Y4DbyGKiFTzWCSVbJxnBZFHRg627/H6JL7E7TIT6gAg989AfiHL/Zdv1S5fEIS2eSGVTpBmUkVwenfaon51ERccR7KVWvnzJTIlXCED+ADBGWH37+9ozPq9oGd51lYOM4K7N68gfoT7Fm42jeJRQ2rGmGchcSeQwllIQoT32Ogg5xUsK+0Qf7bc131QvJ+3Snk/r9Lmq", "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 p2F742udNjpquDKzD/7V3zViRHsKBkX8qFf+iweKMVPbprCexq6Mqpe+uROqXlG4dSwSdHAnkLLYmSRHU90TqkqbkbWUt4TOIQOFAL0TcxkypyK6ji3wjVFyWbBrJh96x4bgJFsJW3ubJ4XSVU/+FAlkAKp99j4OPPfjOdarHgNv+IGeO7fis+OuDt6tjMy0CiVhHaaPfrycq1htDVVHDskfGdau9i6zQjoQBjhcF08+oBZO0hewKl5VG78jbucsCik4fPoarjRql7gU3ORI0pKbv1KSV+hWN4CLfbSOBzGvAP1gCqHoFSetRuVfKJ2X2o7B+o3mRP2K2Ps+GMvnKWH+nh4nrRXvbXoaE/5GmiutG1hFND7B2mJqJiEQwMwCpSpO1C0x6JXpXwBLqC1SU/AXn+Hwv9jf61e4vve5aa47fuJy57U2MTCAGZIe2czLMNI1K1Ed9brHHoXwTeHFnMQLhnlMKCpNb42lHYs1vdllIn03hYDRNdpZGmOn9uD2YMJ/AbScgLU3hRhEIBDqJZanEuFWJsu6tmZdbqRi2pLOyAmKFQ0cA4FejctULdsvLNRyphsnJfeISqpnJjzLfnKcUcHh1HVvr1xicR4y+ZGjqe+Bo48IWYbPfek4RZYnQne/6549i/haWkPOTDs0KCjbWjQMQFJc2rgtMpudEZg+CMvJfVjw2eojrapNZahcVkbduSUxwLSkQrM9oRWTzPBYG60HjyQsnV99SOzJg/VSUhehUi8q/NFxEg8GdYydBLBnZ+N8yb9omL2C1Ux2tdr7sKW6hOgnBDyPxNhb7YL6knbtz6h8Lh8f6T+i42sWNZpocskfJGP9V7+7PU7fg9K+86vioHtxbSLoOeZKsTE61YUu84pHGC8XSGR0OplR6S6rr+iUlIYrGyC7RraZrmpvU+8tiwBWJ6SQKBh12QRSOsGxoS5kIh+9a9CzJLW1Yx2+sd+c2tGgJdDDD1zX5GZgErc2hqr+Org72UryC6TxHdukqJrweyJvTnueOubiRByr0q+K8TKyjRe1HcRh+QWLvwLHTYwn8IfWxfe4OTBMwDZuU6qclzXofNTbD69u4w+zkF5yzYuODAcGbeuWXWgmuUuCdNhcSVvzmWSs+nvD9Uh3e3oFYboz8fZh/jSO7lEJRwvRQI/HfZmJ/nZC4I6zHPEYtYbqMD+Crxm+MJL3jlF128CUOUECCPU90lhSW6ZWkYR2O/4mbhPveNmfzyKUJRUHz3RqMxllp001+RZSDy++b3W512uIY6pGqesY30ughq+wU3FSZ15raOuD/oshQYBd6VoI5vTWCqjL1LDehfnAFLEfxHjfo/YDwR6Wy/AD3+FiYLMYSEcnf9nRYdej8HkL+s/1rh9/IPEV+uDtWX8vdsgNizvKl4idYuxFHSzfvhyFK+M2UW/Vg0SM1wF+9ITrztvzBasnD2GFFbFdDJgD7zAZRQ7Jc+zJobbqvB6mNhrockIeWEEL1UMQRez33FkP9DA8rNC5DvcM/u+o7JU7kY2EpiNowqjrJ+IybWi5R0gNDydirXNVJPeQpNPe0NDBLKbsqbqTJv3dYa0xpm92C9rdYF+W+6usuqoUbNLeqCZfXbaYYyGLOfjsCGk7BQvbme5GB2AdyoXI/N4=", "X-OriginatorOrg": "valinux.co.jp", "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 1f9fab2d-e9a2-4516-cdf9-08de3d7f4521", "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:36.4009\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 yAA92okvx5MyQrC4axPVpfSAZmBcjp/khICAHUaUBmiqyvSJtpvvpQEToMkVNKzcxwNnoI9b65lEjZXoIBkBAQ==", "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "TYCP286MB2863" }, "content": "Add a helper library under drivers/ntb/hw/edma/ that is to be used by\nthe NTB transport remote eDMA backend. This is not an NTB hardware\ndriver but rather encapsulates DesignWare eDMA specific plumbing.\n\nSigned-off-by: Koichiro Den <den@valinux.co.jp>\n---\n drivers/ntb/hw/edma/ntb_hw_edma.c | 754 ++++++++++++++++++++++++++++++\n drivers/ntb/hw/edma/ntb_hw_edma.h | 76 +++\n 2 files changed, 830 insertions(+)\n create mode 100644 drivers/ntb/hw/edma/ntb_hw_edma.c\n create mode 100644 drivers/ntb/hw/edma/ntb_hw_edma.h", "diff": "diff --git a/drivers/ntb/hw/edma/ntb_hw_edma.c b/drivers/ntb/hw/edma/ntb_hw_edma.c\nnew file mode 100644\nindex 000000000000..50c4ddee285f\n--- /dev/null\n+++ b/drivers/ntb/hw/edma/ntb_hw_edma.c\n@@ -0,0 +1,754 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * NTB remote DesignWare eDMA helpers\n+ *\n+ * This file is a helper library used by the NTB transport remote-eDMA backend,\n+ * not a standalone NTB hardware driver. It contains the DesignWare eDMA\n+ * specific plumbing needed to expose/map peer-accessible resources via an NTB\n+ * memory window and to manage DMA channels and peer notifications.\n+ */\n+\n+#include <linux/dma/edma.h>\n+#include <linux/dmaengine.h>\n+#include <linux/device.h>\n+#include <linux/iommu.h>\n+#include <linux/irqdomain.h>\n+#include <linux/ntb.h>\n+#include <linux/pci.h>\n+#include <linux/pci-epc.h>\n+#include <linux/spinlock.h>\n+\n+#include \"ntb_hw_edma.h\"\n+\n+/* Default eDMA LLP memory size */\n+#define DMA_LLP_MEM_SIZE\tPAGE_SIZE\n+\n+#define NTB_EDMA_MW_IDX_INVALID\t(-1)\n+\n+struct ntb_edma_ctx {\n+\tbool initialized;\n+\n+\t/* Fields for the notification handling */\n+\tu32 qp_count;\n+\tu32 *notify_src_virt;\n+\tdma_addr_t notify_src_phys;\n+\tstruct scatterlist sgl;\n+\n+\t/* Host to EP scratch buffer to tell the event info */\n+\tunion {\n+\t\tstruct ntb_edma_db *db_virt;\n+\t\tstruct ntb_edma_db __iomem *db_io;\n+\t};\n+\tdma_addr_t db_phys;\n+\n+\t/* Below are the records for teardown path */\n+\n+\t/* For ntb_edma_info to be unmapped on teardown */\n+\tstruct ntb_edma_info *info_virt;\n+\tdma_addr_t info_phys;\n+\tsize_t info_bytes;\n+\n+\tint mw_index;\n+\tbool mw_trans_set;\n+\n+\t/* eDMA register window IOMMU mapping (EP side) */\n+\tbool reg_mapped;\n+\tstruct iommu_domain *iommu_dom;\n+\tunsigned long reg_iova;\n+\tsize_t reg_iova_size;\n+\n+\t/* Read channels delegated to the host side (EP side) */\n+\tstruct dma_chan *dchan[NTB_EDMA_TOTAL_CH_NUM];\n+\n+\t/* RC-side state */\n+\tbool peer_initialized;\n+\tbool peer_probed;\n+\tstruct dw_edma_chip *peer_chip;\n+\tvoid __iomem *peer_virt;\n+\tresource_size_t peer_virt_size;\n+};\n+\n+typedef void (*ntb_edma_interrupt_cb_t)(void *data, int qp_num);\n+\n+struct ntb_edma_interrupt {\n+\tntb_edma_interrupt_cb_t cb;\n+\tvoid *data;\n+};\n+\n+struct ntb_edma_filter {\n+\tstruct device *dma_dev;\n+\tu32 direction;\n+};\n+\n+static struct ntb_edma_ctx edma_ctx;\n+static struct ntb_edma_interrupt intr;\n+\n+static DEFINE_SPINLOCK(ntb_edma_notify_lock);\n+\n+static bool ntb_edma_filter_fn(struct dma_chan *chan, void *arg)\n+{\n+\tstruct ntb_edma_filter *filter = arg;\n+\tu32 dir = filter->direction;\n+\tstruct dma_slave_caps caps;\n+\tint ret;\n+\n+\tif (chan->device->dev != filter->dma_dev)\n+\t\treturn false;\n+\n+\tret = dma_get_slave_caps(chan, &caps);\n+\tif (ret < 0)\n+\t\treturn false;\n+\n+\treturn !!(caps.directions & dir);\n+}\n+\n+static void ntb_edma_notify_cb(struct dma_chan *dchan, void *data)\n+{\n+\tstruct ntb_edma_interrupt *v = data;\n+\tntb_edma_interrupt_cb_t cb;\n+\tstruct ntb_edma_db *db;\n+\tvoid *cb_data;\n+\tu32 qp_count;\n+\tu32 i, val;\n+\n+\tguard(spinlock_irqsave)(&ntb_edma_notify_lock);\n+\n+\tcb = v->cb;\n+\tcb_data = v->data;\n+\tqp_count = edma_ctx.qp_count;\n+\tdb = edma_ctx.db_virt;\n+\tif (!cb || !db)\n+\t\treturn;\n+\n+\tfor (i = 0; i < qp_count; i++) {\n+\t\tval = READ_ONCE(db->db[i]);\n+\t\tif (!val)\n+\t\t\tcontinue;\n+\n+\t\tWRITE_ONCE(db->db[i], 0);\n+\t\tcb(cb_data, i);\n+\t}\n+}\n+\n+static void ntb_edma_undelegate_chans(struct ntb_edma_ctx *ctx)\n+{\n+\tunsigned int i;\n+\n+\tif (!ctx)\n+\t\treturn;\n+\n+\tscoped_guard(spinlock_irqsave, &ntb_edma_notify_lock) {\n+\t\tintr.cb = NULL;\n+\t\tintr.data = NULL;\n+\t}\n+\n+\tfor (i = 0; i < NTB_EDMA_TOTAL_CH_NUM; i++) {\n+\t\tif (!ctx->dchan[i])\n+\t\t\tcontinue;\n+\n+\t\tif (i == NTB_EDMA_CH_NUM)\n+\t\t\tdw_edma_chan_register_notify(ctx->dchan[i], NULL, NULL);\n+\n+\t\tdma_release_channel(ctx->dchan[i]);\n+\t\tctx->dchan[i] = NULL;\n+\t}\n+}\n+\n+static int ntb_edma_delegate_chans(struct device *dev, struct ntb_edma_ctx *ctx,\n+\t\t\t\t struct ntb_edma_info *info,\n+\t\t\t\t ntb_edma_interrupt_cb_t cb, void *data)\n+{\n+\tstruct ntb_edma_filter filter;\n+\tstruct dw_edma_region region;\n+\tdma_cap_mask_t dma_mask;\n+\tstruct dma_chan *chan;\n+\tunsigned int i;\n+\tint rc;\n+\n+\tdma_cap_zero(dma_mask);\n+\tdma_cap_set(DMA_SLAVE, dma_mask);\n+\n+\tfilter.dma_dev = dev;\n+\n+\t/* Configure read channels, which will be driven by the host side */\n+\tfor (i = 0; i < NTB_EDMA_TOTAL_CH_NUM; i++) {\n+\t\tfilter.direction = BIT(DMA_DEV_TO_MEM);\n+\t\tchan = dma_request_channel(dma_mask, ntb_edma_filter_fn,\n+\t\t\t\t\t &filter);\n+\t\tif (!chan) {\n+\t\t\trc = -ENODEV;\n+\t\t\tgoto err;\n+\t\t}\n+\t\tctx->dchan[i] = chan;\n+\n+\t\tif (i == NTB_EDMA_CH_NUM) {\n+\t\t\tscoped_guard(spinlock_irqsave, &ntb_edma_notify_lock) {\n+\t\t\t\tintr.cb = cb;\n+\t\t\t\tintr.data = data;\n+\t\t\t}\n+\t\t\trc = dw_edma_chan_register_notify(\n+\t\t\t\t\tchan, ntb_edma_notify_cb, &intr);\n+\t\t\tif (rc)\n+\t\t\t\tgoto err;\n+\t\t} else {\n+\t\t\trc = dw_edma_chan_irq_config(chan, DW_EDMA_CH_IRQ_REMOTE);\n+\t\t\tif (rc)\n+\t\t\t\tdev_warn(dev, \"irq config failed (i=%u %d)\\n\",\n+\t\t\t\t\t i, rc);\n+\t\t}\n+\n+\t\trc = dw_edma_chan_get_ll_region(chan, ®ion);\n+\t\tif (rc)\n+\t\t\tgoto err;\n+\n+\t\tinfo->ll_rd_phys[i] = region.paddr;\n+\t}\n+\n+\treturn 0;\n+\n+err:\n+\tntb_edma_undelegate_chans(ctx);\n+\treturn rc;\n+}\n+\n+static void ntb_edma_ctx_reset(struct ntb_edma_ctx *ctx)\n+{\n+\tctx->initialized = false;\n+\tctx->mw_index = NTB_EDMA_MW_IDX_INVALID;\n+\tctx->mw_trans_set = false;\n+\tctx->reg_mapped = false;\n+\tctx->iommu_dom = NULL;\n+\tctx->reg_iova = 0;\n+\tctx->reg_iova_size = 0;\n+\tctx->db_phys = 0;\n+\tctx->qp_count = 0;\n+\tctx->info_virt = NULL;\n+\tctx->info_phys = 0;\n+\tctx->info_bytes = 0;\n+\tctx->db_virt = NULL;\n+\tmemset(ctx->dchan, 0, sizeof(ctx->dchan));\n+}\n+\n+int ntb_edma_setup_mws(struct ntb_dev *ndev, int mw_index,\n+\t\t unsigned int qp_count, ntb_edma_interrupt_cb_t cb,\n+\t\t void *data)\n+{\n+\tstruct ntb_edma_ctx *ctx = &edma_ctx;\n+\tconst size_t info_bytes = PAGE_SIZE;\n+\tresource_size_t size_max, offset;\n+\tdma_addr_t db_phys, info_phys;\n+\tsize_t reg_size, reg_size_mw;\n+\tstruct ntb_edma_info *info;\n+\tphys_addr_t edma_reg_phys;\n+\tstruct iommu_domain *dom;\n+\tstruct ntb_edma_db *db;\n+\tsize_t ll_bytes, size;\n+\tstruct pci_epc *epc;\n+\tstruct device *dev;\n+\tunsigned long iova;\n+\tphys_addr_t phys;\n+\tu64 need;\n+\tint rc;\n+\tu32 i;\n+\n+\tif (ctx->initialized)\n+\t\treturn 0;\n+\n+\t/* Clean up stale state from a previous failed attempt. */\n+\tntb_edma_teardown_mws(ndev);\n+\n+\tepc = (struct pci_epc *)ntb_get_private_data(ndev);\n+\tif (!epc)\n+\t\treturn -ENODEV;\n+\tdev = epc->dev.parent;\n+\n+\tntb_edma_ctx_reset(ctx);\n+\n+\tctx->mw_index = mw_index;\n+\tctx->qp_count = qp_count;\n+\n+\tinfo = dma_alloc_coherent(dev, info_bytes, &info_phys, GFP_KERNEL);\n+\tif (!info)\n+\t\treturn -ENOMEM;\n+\tmemset(info, 0, info_bytes);\n+\n+\tctx->info_virt = info;\n+\tctx->info_phys = info_phys;\n+\tctx->info_bytes = info_bytes;\n+\n+\t/* Get eDMA reg base and size, IOMMU map it if necessary */\n+\trc = dw_edma_get_reg_window(epc, &edma_reg_phys, ®_size);\n+\tif (rc) {\n+\t\tdev_err(&ndev->pdev->dev,\n+\t\t\t\"failed to get eDMA register window: %d\\n\", rc);\n+\t\tgoto err;\n+\t}\n+\tdom = iommu_get_domain_for_dev(dev);\n+\tif (dom) {\n+\t\tphys = edma_reg_phys & PAGE_MASK;\n+\t\tsize = PAGE_ALIGN(reg_size + edma_reg_phys - phys);\n+\t\tiova = phys;\n+\n+\t\trc = iommu_map(dom, iova, phys, size,\n+\t\t\t IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO,\n+\t\t\t GFP_KERNEL);\n+\t\tif (rc) {\n+\t\t\tdev_err(&ndev->dev,\n+\t\t\t\t\"failed to direct map eDMA reg: %d\\n\", rc);\n+\t\t\tgoto err;\n+\t\t}\n+\n+\t\tctx->reg_mapped = true;\n+\t\tctx->iommu_dom = dom;\n+\t\tctx->reg_iova = iova;\n+\t\tctx->reg_iova_size = size;\n+\t}\n+\n+\t/* Read channels are driven by the peer (host side) */\n+\trc = ntb_edma_delegate_chans(dev, ctx, info, cb, data);\n+\tif (rc) {\n+\t\tdev_err(&ndev->pdev->dev,\n+\t\t\t\"failed to prepare channels to delegate: %d\\n\", rc);\n+\t\tgoto err;\n+\t}\n+\n+\t/* Scratch buffer for notification */\n+\tdb = dma_alloc_coherent(dev, sizeof(*db), &db_phys, GFP_KERNEL);\n+\tif (!db) {\n+\t\trc = -ENOMEM;\n+\t\tgoto err;\n+\t}\n+\tmemset(db, 0, sizeof(*db));\n+\n+\tctx->db_virt = db;\n+\tctx->db_phys = db_phys;\n+\n+\t/* Prep works for IB iATU mappings */\n+\tll_bytes = NTB_EDMA_TOTAL_CH_NUM * DMA_LLP_MEM_SIZE;\n+\treg_size_mw = roundup_pow_of_two(reg_size);\n+\tneed = info_bytes + PAGE_SIZE + reg_size_mw + ll_bytes;\n+\n+\trc = ntb_mw_get_align(ndev, 0, mw_index, NULL, NULL, &size_max, &offset);\n+\tif (rc)\n+\t\tgoto err;\n+\n+\tif (size_max < need) {\n+\t\trc = -ENOSPC;\n+\t\tgoto err;\n+\t}\n+\n+\t/* iATU map ntb_edma_info */\n+\trc = ntb_mw_set_trans(ndev, 0, mw_index, info_phys, info_bytes, offset);\n+\tif (rc)\n+\t\tgoto err;\n+\tctx->mw_trans_set = true;\n+\toffset += info_bytes;\n+\n+\t/* iATU map ntb_edma_db */\n+\trc = ntb_mw_set_trans(ndev, 0, mw_index, db_phys, PAGE_SIZE, offset);\n+\tif (rc)\n+\t\tgoto err;\n+\toffset += PAGE_SIZE;\n+\n+\t/* iATU map eDMA reg */\n+\trc = ntb_mw_set_trans(ndev, 0, mw_index, edma_reg_phys, reg_size_mw,\n+\t\t\t offset);\n+\tif (rc)\n+\t\tgoto err;\n+\toffset += reg_size_mw;\n+\n+\t/* iATU map LL location */\n+\tfor (i = 0; i < NTB_EDMA_TOTAL_CH_NUM; i++) {\n+\t\trc = ntb_mw_set_trans(ndev, 0, mw_index, info->ll_rd_phys[i],\n+\t\t\t\t DMA_LLP_MEM_SIZE, offset);\n+\t\tif (rc)\n+\t\t\tgoto err;\n+\t\toffset += DMA_LLP_MEM_SIZE;\n+\t}\n+\n+\t/* Fill in info */\n+\tinfo->magic = NTB_EDMA_INFO_MAGIC;\n+\tinfo->reg_size = reg_size_mw;\n+\tinfo->ch_cnt = NTB_EDMA_TOTAL_CH_NUM;\n+\tinfo->db_base = db_phys;\n+\n+\tctx->initialized = true;\n+\treturn 0;\n+\n+err:\n+\tntb_edma_teardown_mws(ndev);\n+\treturn rc;\n+}\n+\n+static int ntb_edma_irq_vector(struct device *dev, unsigned int nr)\n+{\n+\tstruct pci_dev *pdev = to_pci_dev(dev);\n+\tint ret, nvec;\n+\n+\tnvec = pci_msi_vec_count(pdev);\n+\tfor (; nr < nvec; nr++) {\n+\t\tret = pci_irq_vector(pdev, nr);\n+\t\tif (!irq_has_action(ret))\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+static const struct dw_edma_plat_ops ntb_edma_ops = {\n+\t.irq_vector = ntb_edma_irq_vector,\n+};\n+\n+int ntb_edma_setup_peer(struct ntb_dev *ndev, int mw_index,\n+\t\t\tunsigned int qp_count)\n+{\n+\tstruct ntb_edma_ctx *ctx = &edma_ctx;\n+\tstruct ntb_edma_info __iomem *info;\n+\tstruct dw_edma_chip *chip;\n+\tvoid __iomem *edma_virt;\n+\tresource_size_t mw_size;\n+\tphys_addr_t edma_phys;\n+\tunsigned int ch_cnt;\n+\tunsigned int i;\n+\tint ret;\n+\tu64 off;\n+\n+\tif (ctx->peer_initialized)\n+\t\treturn 0;\n+\n+\t/* Clean up stale state from a previous failed attempt. */\n+\tntb_edma_teardown_peer(ndev);\n+\n+\tret = ntb_peer_mw_get_addr(ndev, mw_index, &edma_phys, &mw_size);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tedma_virt = ioremap(edma_phys, mw_size);\n+\tif (!edma_virt)\n+\t\treturn -ENOMEM;\n+\n+\tctx->peer_virt = edma_virt;\n+\tctx->peer_virt_size = mw_size;\n+\n+\tinfo = edma_virt;\n+\tif (readl(&info->magic) != NTB_EDMA_INFO_MAGIC) {\n+\t\tret = -EINVAL;\n+\t\tgoto err;\n+\t}\n+\n+\tch_cnt = readw(&info->ch_cnt);\n+\tif (ch_cnt != NTB_EDMA_TOTAL_CH_NUM) {\n+\t\tret = -EINVAL;\n+\t\tgoto err;\n+\t}\n+\n+\tchip = devm_kzalloc(&ndev->dev, sizeof(*chip), GFP_KERNEL);\n+\tif (!chip) {\n+\t\tret = -ENOMEM;\n+\t\tgoto err;\n+\t}\n+\n+\toff = 2 * PAGE_SIZE;\n+\tchip->dev = &ndev->pdev->dev;\n+\tchip->nr_irqs = 4;\n+\tchip->ops = &ntb_edma_ops;\n+\tchip->flags = 0;\n+\tchip->reg_base = edma_virt + off;\n+\tchip->mf = EDMA_MF_EDMA_UNROLL;\n+\tchip->ll_wr_cnt = 0;\n+\tchip->ll_rd_cnt = ch_cnt;\n+\n+\tctx->db_io = (void __iomem *)edma_virt + PAGE_SIZE;\n+\tctx->qp_count = qp_count;\n+\tctx->db_phys = readq(&info->db_base);\n+\n+\tctx->notify_src_virt = dma_alloc_coherent(&ndev->pdev->dev,\n+\t\t\t\t\t\t sizeof(*ctx->notify_src_virt),\n+\t\t\t\t\t\t &ctx->notify_src_phys,\n+\t\t\t\t\t\t GFP_KERNEL);\n+\tif (!ctx->notify_src_virt) {\n+\t\tret = -ENOMEM;\n+\t\tgoto err;\n+\t}\n+\n+\toff += readl(&info->reg_size);\n+\n+\tfor (i = 0; i < ch_cnt; i++) {\n+\t\tchip->ll_region_rd[i].vaddr.io = edma_virt + off;\n+\t\tchip->ll_region_rd[i].paddr = readq(&info->ll_rd_phys[i]);\n+\t\tchip->ll_region_rd[i].sz = DMA_LLP_MEM_SIZE;\n+\t\toff += DMA_LLP_MEM_SIZE;\n+\t}\n+\n+\tif (!pci_dev_msi_enabled(ndev->pdev)) {\n+\t\tret = -ENXIO;\n+\t\tgoto err;\n+\t}\n+\n+\tret = dw_edma_probe(chip);\n+\tif (ret) {\n+\t\tdev_err(&ndev->dev, \"dw_edma_probe failed: %d\\n\", ret);\n+\t\tgoto err;\n+\t}\n+\n+\tctx->peer_chip = chip;\n+\tctx->peer_probed = true;\n+\tctx->peer_initialized = true;\n+\treturn 0;\n+\n+err:\n+\tntb_edma_teardown_peer(ndev);\n+\treturn ret;\n+}\n+\n+void ntb_edma_teardown_mws(struct ntb_dev *ndev)\n+{\n+\tstruct ntb_edma_ctx *ctx = &edma_ctx;\n+\tstruct device *dev = NULL;\n+\tstruct pci_epc *epc;\n+\tstruct ntb_edma_db *db;\n+\tstruct ntb_edma_info *info;\n+\tdma_addr_t db_phys, info_phys;\n+\tsize_t info_bytes;\n+\n+\tepc = (struct pci_epc *)ntb_get_private_data(ndev);\n+\tWARN_ON(!epc);\n+\tif (epc)\n+\t\tdev = epc->dev.parent;\n+\n+\tscoped_guard(spinlock_irqsave, &ntb_edma_notify_lock) {\n+\t\tdb = ctx->db_virt;\n+\t\tdb_phys = ctx->db_phys;\n+\n+\t\t/* Make callbacks no-op first. */\n+\t\tintr.cb = NULL;\n+\t\tintr.data = NULL;\n+\t\tctx->db_virt = NULL;\n+\t\tctx->qp_count = 0;\n+\t}\n+\n+\tinfo = ctx->info_virt;\n+\tinfo_phys = ctx->info_phys;\n+\tinfo_bytes = ctx->info_bytes;\n+\n+\t/* Disconnect the MW before freeing its backing memory */\n+\tif (ctx->mw_trans_set && ctx->mw_index != NTB_EDMA_MW_IDX_INVALID)\n+\t\tntb_mw_clear_trans(ndev, 0, ctx->mw_index);\n+\n+\tntb_edma_undelegate_chans(ctx);\n+\n+\tif (ctx->reg_mapped)\n+\t\tiommu_unmap(ctx->iommu_dom, ctx->reg_iova, ctx->reg_iova_size);\n+\n+\tif (db && dev)\n+\t\tdma_free_coherent(dev, sizeof(*db), db, db_phys);\n+\n+\tif (info && dev && info_bytes)\n+\t\tdma_free_coherent(dev, info_bytes, info, info_phys);\n+\n+\tntb_edma_ctx_reset(ctx);\n+}\n+\n+void ntb_edma_teardown_peer(struct ntb_dev *ndev)\n+{\n+\tstruct ntb_edma_ctx *ctx = &edma_ctx;\n+\tvoid __iomem *peer_virt = ctx->peer_virt;\n+\tstruct dw_edma_chip *chip = ctx->peer_chip;\n+\tu32 *notify_src = ctx->notify_src_virt;\n+\tdma_addr_t notify_src_phys = ctx->notify_src_phys;\n+\n+\t/* Stop using peer MMIO early. */\n+\tctx->db_io = NULL;\n+\tctx->db_phys = 0;\n+\tctx->qp_count = 0;\n+\n+\tif (ctx->peer_probed && chip)\n+\t\tdw_edma_remove(chip);\n+\n+\tctx->peer_initialized = false;\n+\tctx->peer_probed = false;\n+\tctx->peer_chip = NULL;\n+\n+\tif (notify_src)\n+\t\tdma_free_coherent(&ndev->pdev->dev, sizeof(*notify_src),\n+\t\t\t\t notify_src, notify_src_phys);\n+\n+\tctx->notify_src_virt = NULL;\n+\tctx->notify_src_phys = 0;\n+\tmemset(&ctx->sgl, 0, sizeof(ctx->sgl));\n+\n+\tif (peer_virt)\n+\t\tiounmap(peer_virt);\n+\n+\tctx->peer_virt = NULL;\n+\tctx->peer_virt_size = 0;\n+}\n+\n+void ntb_edma_teardown_chans(struct ntb_edma_chans *edma)\n+{\n+\tunsigned int i;\n+\n+\tif (!edma)\n+\t\treturn;\n+\n+\tfor (i = 0; i < NTB_EDMA_CH_NUM; i++) {\n+\t\tif (!edma->chan[i])\n+\t\t\tcontinue;\n+\t\tdma_release_channel(edma->chan[i]);\n+\t\tedma->chan[i] = NULL;\n+\t}\n+\tedma->num_chans = 0;\n+\n+\tif (edma->intr_chan) {\n+\t\tdma_release_channel(edma->intr_chan);\n+\t\tedma->intr_chan = NULL;\n+\t}\n+\n+\tatomic_set(&edma->cur_chan, 0);\n+}\n+\n+int ntb_edma_setup_chans(struct device *dev, struct ntb_edma_chans *edma,\n+\t\t\t bool remote)\n+{\n+\tstruct ntb_edma_filter filter;\n+\tdma_cap_mask_t dma_mask;\n+\tunsigned int i;\n+\tint rc;\n+\n+\tdma_cap_zero(dma_mask);\n+\tdma_cap_set(DMA_SLAVE, dma_mask);\n+\n+\tmemset(edma, 0, sizeof(*edma));\n+\tedma->dev = dev;\n+\n+\tmutex_init(&edma->lock);\n+\n+\tfilter.dma_dev = dev;\n+\tfilter.direction = BIT(DMA_MEM_TO_DEV);\n+\tfor (i = 0; i < NTB_EDMA_CH_NUM; i++) {\n+\t\tedma->chan[i] = dma_request_channel(\n+\t\t\t\t\tdma_mask, ntb_edma_filter_fn, &filter);\n+\t\tif (!edma->chan[i])\n+\t\t\tbreak;\n+\t\tedma->num_chans++;\n+\n+\t\tif (remote)\n+\t\t\trc = dw_edma_chan_irq_config(edma->chan[i],\n+\t\t\t\t\t\t DW_EDMA_CH_IRQ_REMOTE);\n+\t\telse\n+\t\t\trc = dw_edma_chan_irq_config(edma->chan[i],\n+\t\t\t\t\t\t DW_EDMA_CH_IRQ_LOCAL);\n+\n+\t\tif (rc) {\n+\t\t\tdev_err(dev, \"irq config failed on ch%u: %d\\n\", i, rc);\n+\t\t\tgoto err;\n+\t\t}\n+\t}\n+\n+\tif (!edma->num_chans) {\n+\t\tdev_warn(dev, \"Remote eDMA channels failed to initialize\\n\");\n+\t\tntb_edma_teardown_chans(edma);\n+\t\treturn -ENODEV;\n+\t}\n+\treturn 0;\n+err:\n+\tntb_edma_teardown_chans(edma);\n+\treturn rc;\n+}\n+\n+int ntb_edma_setup_intr_chan(struct device *dev, struct ntb_edma_chans *edma)\n+{\n+\tstruct ntb_edma_filter filter;\n+\tdma_cap_mask_t dma_mask;\n+\tstruct dma_slave_config cfg;\n+\tstruct scatterlist *sgl = &edma_ctx.sgl;\n+\tint rc;\n+\n+\tif (edma->intr_chan)\n+\t\treturn 0;\n+\n+\tif (!edma_ctx.notify_src_virt || !edma_ctx.db_phys)\n+\t\treturn -EINVAL;\n+\n+\tdma_cap_zero(dma_mask);\n+\tdma_cap_set(DMA_SLAVE, dma_mask);\n+\n+\tfilter.dma_dev = dev;\n+\tfilter.direction = BIT(DMA_MEM_TO_DEV);\n+\n+\tedma->intr_chan = dma_request_channel(dma_mask, ntb_edma_filter_fn,\n+\t\t\t\t\t &filter);\n+\tif (!edma->intr_chan) {\n+\t\tdev_warn(dev,\n+\t\t\t \"Remote eDMA notify channel could not be allocated\\n\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\trc = dw_edma_chan_irq_config(edma->intr_chan, DW_EDMA_CH_IRQ_LOCAL);\n+\tif (rc)\n+\t\tgoto err_release;\n+\n+\t/* Ensure store is visible before kicking DMA transfer */\n+\twmb();\n+\n+\tsg_init_table(sgl, 1);\n+\tsg_dma_address(sgl) = edma_ctx.notify_src_phys;\n+\tsg_dma_len(sgl) = sizeof(u32);\n+\n+\tmemset(&cfg, 0, sizeof(cfg));\n+\tcfg.dst_addr = edma_ctx.db_phys; /* The first 32bit is 'target' */\n+\tcfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;\n+\tcfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;\n+\tcfg.direction = DMA_MEM_TO_DEV;\n+\n+\trc = dmaengine_slave_config(edma->intr_chan, &cfg);\n+\tif (rc)\n+\t\tgoto err_release;\n+\n+\treturn 0;\n+\n+err_release:\n+\tdma_release_channel(edma->intr_chan);\n+\tedma->intr_chan = NULL;\n+\treturn rc;\n+}\n+\n+struct dma_chan *ntb_edma_pick_chan(struct ntb_edma_chans *edma,\n+\t\t\t\t unsigned int idx)\n+{\n+\treturn edma->chan[idx % edma->num_chans];\n+}\n+\n+int ntb_edma_notify_peer(struct ntb_edma_chans *edma, int qp_num)\n+{\n+\tstruct dma_async_tx_descriptor *txd;\n+\tdma_cookie_t cookie;\n+\n+\tif (!edma || !edma->intr_chan)\n+\t\treturn -ENXIO;\n+\n+\tif (qp_num < 0 || qp_num >= edma_ctx.qp_count)\n+\t\treturn -EINVAL;\n+\n+\tif (!edma_ctx.db_io)\n+\t\treturn -EINVAL;\n+\n+\tguard(mutex)(&edma->lock);\n+\n+\twritel(1, &edma_ctx.db_io->db[qp_num]);\n+\n+\t/* Ensure store is visible before kicking the DMA transfer */\n+\twmb();\n+\n+\ttxd = dmaengine_prep_slave_sg(edma->intr_chan, &edma_ctx.sgl, 1,\n+\t\t\t\t DMA_MEM_TO_DEV,\n+\t\t\t\t DMA_CTRL_ACK | DMA_PREP_INTERRUPT);\n+\tif (!txd)\n+\t\treturn -ENOSPC;\n+\n+\tcookie = dmaengine_submit(txd);\n+\tif (dma_submit_error(cookie))\n+\t\treturn -ENOSPC;\n+\n+\tdma_async_issue_pending(edma->intr_chan);\n+\treturn 0;\n+}\ndiff --git a/drivers/ntb/hw/edma/ntb_hw_edma.h b/drivers/ntb/hw/edma/ntb_hw_edma.h\nnew file mode 100644\nindex 000000000000..46b50e504389\n--- /dev/null\n+++ b/drivers/ntb/hw/edma/ntb_hw_edma.h\n@@ -0,0 +1,76 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+\n+#ifndef _NTB_HW_EDMA_H_\n+#define _NTB_HW_EDMA_H_\n+\n+#include <linux/completion.h>\n+#include <linux/device.h>\n+#include <linux/interrupt.h>\n+\n+#define NTB_EDMA_CH_NUM\t\t4\n+\n+/* One extra channel is reserved for notification (RC to EP interrupt kick). */\n+#define NTB_EDMA_TOTAL_CH_NUM\t(NTB_EDMA_CH_NUM + 1)\n+\n+#define NTB_EDMA_INFO_MAGIC\t0x45444D41 /* \"EDMA\" */\n+\n+#define NTB_EDMA_NOTIFY_MAX_QP\t64\n+\n+typedef void (*ntb_edma_interrupt_cb_t)(void *data, int qp_num);\n+\n+/*\n+ * REMOTE_EDMA_EP:\n+ * Endpoint owns the eDMA engine and pushes descriptors into a shared MW.\n+ *\n+ * REMOTE_EDMA_RC:\n+ * Root Complex controls the endpoint eDMA through the shared MW and\n+ * drives reads/writes on behalf of the host.\n+ */\n+typedef enum {\n+\tREMOTE_EDMA_UNKNOWN,\n+\tREMOTE_EDMA_EP,\n+\tREMOTE_EDMA_RC,\n+} remote_edma_mode_t;\n+\n+struct ntb_edma_info {\n+\tu32 magic;\n+\tu32 reg_size;\n+\tu16 ch_cnt;\n+\tu64 db_base;\n+\tu64 ll_rd_phys[NTB_EDMA_TOTAL_CH_NUM];\n+};\n+\n+struct ntb_edma_db {\n+\tu32 target;\n+\tu32 db[NTB_EDMA_NOTIFY_MAX_QP];\n+};\n+\n+struct ntb_edma_chans {\n+\tstruct device *dev;\n+\n+\tstruct dma_chan *chan[NTB_EDMA_CH_NUM];\n+\tstruct dma_chan *intr_chan;\n+\n+\tunsigned int num_chans;\n+\tatomic_t cur_chan;\n+\n+\tstruct mutex lock;\n+};\n+\n+int ntb_edma_setup_mws(struct ntb_dev *ndev, int mw_index,\n+\t\t unsigned int qp_count, ntb_edma_interrupt_cb_t cb,\n+\t\t void *data);\n+int ntb_edma_setup_peer(struct ntb_dev *ndev, int mw_index,\n+\t\t\tunsigned int qp_count);\n+void ntb_edma_teardown_mws(struct ntb_dev *ndev);\n+void ntb_edma_teardown_peer(struct ntb_dev *ndev);\n+int ntb_edma_setup_chans(struct device *dma_dev, struct ntb_edma_chans *edma,\n+\t\t\t bool remote);\n+int ntb_edma_setup_intr_chan(struct device *dma_dev,\n+\t\t\t struct ntb_edma_chans *edma);\n+struct dma_chan *ntb_edma_pick_chan(struct ntb_edma_chans *edma,\n+\t\t\t\t unsigned int idx);\n+void ntb_edma_teardown_chans(struct ntb_edma_chans *edma);\n+int ntb_edma_notify_peer(struct ntb_edma_chans *edma, int qp_num);\n+\n+#endif\n", "prefixes": [ "RFC", "v3", "25/35" ] }