From patchwork Tue Dec 10 18:37:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yidong Zhang X-Patchwork-Id: 13901916 Received: from NAM11-BN8-obe.outbound.protection.outlook.com (mail-bn8nam11on2085.outbound.protection.outlook.com [40.107.236.85]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 00CC2204560; Tue, 10 Dec 2024 18:37:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.236.85 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733855882; cv=fail; b=liqkqvGQGwkcFaM0xHv7gyA3ObPO7n0ZbJpby9Q2uYgsHQy62w/xjHU4lc+GmTfZ6ITjcEVnNZReWaRxpwjnLoafFGn6GnasEwHU1PokNSHhRePhamPW4SEbE/mz0QpryH7JHa+YwcnPBjmzASHA6kgEpPkMYrGDh+U+TXtyBrE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733855882; c=relaxed/simple; bh=pRujW3q7M3cb6eZ3WLuXAcZf3pSvABOjtEF5U6rvvv0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cr3tX3RdkxROfotMIjzw95R332VFkkISx57q5rWvdBaoajQ6WcnSwZvryqAwtN1P1gamS1J8WYbLSboq4vnsPHVA8uPgD5neyZ9TqR3AVFx4NL1cSDBKU/IOi0mNd9IPAcPu33b4rFC3mZEqz/TyUvWO9z1xUd1egPm6YzVLSxg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=iDdfLECX; arc=fail smtp.client-ip=40.107.236.85 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="iDdfLECX" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=bP0NE9Nt6kq5Fwa1O8DRDbdKdCA3s7Wn+AuxFnWRF4TEwuHxt50vnfFH9LjBpJIuDTl+bni+tttSeljxiX4wSiC10OttZTq0gh5BeQl88ltRO9gJP/zfKPCRh71z1zDKiEf67sSVFlFzjdYLJFKKNmz0k/2GBTbSCPoLLNiwKb9ZEykGmP0nUKCMwhqZNSRpiD4SxngA3nw0iElWGHGxM/ADoha/J3fIEUpeeg8QE3zsCj/jJBe3pg4JKyP6dYXTMxJa9LM21ZCacHohI/eUvTCWpODfiJtK52xBGhtE5v7idEcYhmN1AB517FeM/BQ3LwEWG18JXb5EfTZSf4fbsA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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; bh=tdREsDzyVJR57/05d5vJn3b91G3BJJCrMraFtWha6eg=; b=qt4A7ATn1PjQi1SsZgcpvL0+pDUHOPwdrg4mqeL+vV75Dm1qn/v/2/gk/9oRUlQ+AdZwFMeR4L4DWuZzQ7p1ADJ+9fQGNX/4a2VHjlAXhFqVaecQuem/3Bv6dfkHVD3wFtNMBx+JLaL0j+19jLZy7zaxLs2F3gg8rGm9sxRQpb8hRU+2QFSXdzvrdpLQM+QWMpPTu44ub5pMaEYC23Xe/CBaP4JkhrJKZJ9H0q5LPgKVu+KPv9+NVpzyozAVl5Mb/5yEX8caEASRQ2oFl7Rx1aMkYxiBmeCW3nSA4JOHaMfwuccrTHvnM/i6XtrVB+6JiO1xFfnafYEffjwhyVriEg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=tdREsDzyVJR57/05d5vJn3b91G3BJJCrMraFtWha6eg=; b=iDdfLECXIvIBiKdO4YR7DxFsz9NCVxl47YmIePXDg9j9paO0V6VIKvCRgWeZUWoL5Mk/bVf+39g90CbCVHnSbRjOABytC0Cfmcy+3EikJcLCqcPemTOgma9qye5UZ0eWJYOBQgid7qNDUPWIawRaqdZhU8n2hJTL3axTiTEb36c= Received: from SN7PR04CA0225.namprd04.prod.outlook.com (2603:10b6:806:127::20) by CH0PR12MB8529.namprd12.prod.outlook.com (2603:10b6:610:18d::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8230.12; Tue, 10 Dec 2024 18:37:53 +0000 Received: from SN1PEPF000252A3.namprd05.prod.outlook.com (2603:10b6:806:127:cafe::ca) by SN7PR04CA0225.outlook.office365.com (2603:10b6:806:127::20) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.8230.15 via Frontend Transport; Tue, 10 Dec 2024 18:37:53 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C Received: from SATLEXMB04.amd.com (165.204.84.17) by SN1PEPF000252A3.mail.protection.outlook.com (10.167.242.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.8230.7 via Frontend Transport; Tue, 10 Dec 2024 18:37:53 +0000 Received: from SATLEXMB03.amd.com (10.181.40.144) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Tue, 10 Dec 2024 12:37:52 -0600 Received: from xsjyliu51.xilinx.com (10.180.168.240) by SATLEXMB03.amd.com (10.181.40.144) with Microsoft SMTP Server id 15.1.2507.39 via Frontend Transport; Tue, 10 Dec 2024 12:37:52 -0600 From: Yidong Zhang To: , , , , CC: Yidong Zhang , , DMG Karthik , Nishad Saraf , Prapul Krishnamurthy , Hayden Laccabue Subject: [PATCH V2 1/4] drivers/fpga/amd: Add new driver amd versal-pci Date: Tue, 10 Dec 2024 10:37:30 -0800 Message-ID: <20241210183734.30803-2-yidong.zhang@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241210183734.30803-1-yidong.zhang@amd.com> References: <20241210183734.30803-1-yidong.zhang@amd.com> Precedence: bulk X-Mailing-List: linux-fpga@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Received-SPF: None (SATLEXMB04.amd.com: yidong.zhang@amd.com does not designate permitted sender hosts) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SN1PEPF000252A3:EE_|CH0PR12MB8529:EE_ X-MS-Office365-Filtering-Correlation-Id: aabfae20-d2f1-4bea-08e5-08dd1949c215 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|36860700013|1800799024|376014; X-Microsoft-Antispam-Message-Info: CmT7TenKLtLXaqSBzS9GT8sAk9R5ft/49vjjYOQ7FAeu43iWkOaanlQzQxpQrVwyEuCgntYLN8kANt6dbBoEJm0vLj1nNJypWIgatIcMBjpfQDEUoasd6lZtd/4t0ULqV/m+ijFbAAa9liydb3qFa9QKYfcpie50r2AKGXBlbwkS6cuIySJPC/a55hRkGpMjnvLXF+e6gTLg///3CHragSr9mntd67He+L0zViUc7hf5vK/zxubr8TPbkJ0h/1jh5xVjaIwBUTmEGtBGby/4eb1Nl+RLeDz7aKN+lmMHc6Ro8G0gp51K7/fkLeCA5fqzijs++Yti7YAkJlNoXIq6qy2OzAm/UUAN0bpBsaElUaC8j+4NyPFkZYzCu7g4OQnqbvCYRJ0v1DOhD2MITZ1Ax06rw7PKZqFWOg+g9kX9y1nF4BV3L6vZA1iA90AeZvBRkyEhHgcjgp1byXvJAlFMdilPhlS8mV00xO2HY8DHwkLcqugrI8tDUxPJNA4Qm+D2AaShvMrU3nJmBJzTBrRbPVhLlxbOaxlHMPCUi9OgaEgrIi48eTxBCWrtryg4wxQd+vCHJ/g3gMs4zRIdddFLovk19jSqrSPvyoVt+a6A6DAeoVpn0hJFiCb/65dbGvgFdCSPl2po9xgTWhbQT0MWbb0a+4fIkb7ZtvHX6nfHsPKw47eTYUL9J3e25z9ym1x6O1eItZe0wpi75mxMb6CliQ9jfz1uwpD7HO08KM+cR4xN0nWwE/uK7wUmJNLAVTB9APStqGlNmEm6HsPRo2XIZJHjhhRuxyosPRreW14MN9sl9cEjPSLeBioASVH1naimKsB3kYtezyyeWwOS/D3227TDpil5siCtwMebQisXz7jgfji7iBpN27AYsEXue7G+3n/M39sL2aYwGb85N7bzLUllKV6s9ZWuXcUNpSZuwdptUojvRB1CV5NtkDSo3QmBRL/YEbUnMHe+JaltepV2crVObo7LOM/2Li9/myq7HdG5HjRmYmW0ynf138fSAUFvoN/ZFt4hjPN6YBXYexr9qbLtp4u6e8xxzw132HCvCO7lqbGchTeLV2M0Brh5xubIe/F8dZnTO4wqZr9aFTxP5qDu+d47USvM3Dt0kuQQ06f9gVes8fZl42JOctq/TTeeRSJZaJRmqy621z1D1GMQfcyKTPMD/kNsOokrQRpGnPfHOTgqrJtndQa5cy70ZDvan5G0KTamDNgBVMpwPAbc4gdRFQmNgEfzqXNAvq+FTWAFEXSWCoPDoI2VsCaHRbjEFzKkKm0bCCJZ/9zAZxvb4MKNZd5S13hBnB9J8y6oggK+ownkQt/dT3Ed4rJioBk/Bol1f5YU8tkCLv8daGY+dbboA+GXVe/bVHYSq94C3Qm/Q0HjkLXG8nfbmlvRNX0eaq+zWw7SjNE/c6M/7gBtkm64AVq8PuCnIGvAyOak0eyuTaql2Hvvr1OA+kivFLR/ X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:SATLEXMB04.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(82310400026)(36860700013)(1800799024)(376014);DIR:OUT;SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Dec 2024 18:37:53.5162 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: aabfae20-d2f1-4bea-08e5-08dd1949c215 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: SN1PEPF000252A3.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH0PR12MB8529 AMD Versal based PCIe card, including V70, is designed for AI inference efficiency and is tuned for video analytics and natural language processing applications. The driver architecture: +---------+ Communication +---------+ Remote +-----+------+ | | Channel | | Queue | | | | User PF | <============> | Mgmt PF | <=======>| FW | FPGA | +---------+ +---------+ +-----+------+ PL Data base FW APU FW PL Data (copy) - PL (FPGA Program Logic) - FW (Firmware) There are 2 separate drivers from the original XRT[1] design. - UserPF driver - MgmtPF driver The new AMD versal-pci driver will replace the MgmtPF driver for Versal PCIe card. The XRT[1] is already open-sourced. It includes solution of runtime for many different type of PCIe Based cards. It also provides utilities for managing and programming the devices. The AMD versal-pci stands for AMD Versal brand PCIe device management driver. This driver provides the following functionalities: - module and PCI device initialization this driver will attach to specific device id of V70 card; the driver will initialize itself based on bar resources for - communication channel: a hardware message service between mgmt PF and user PF - remote queue: a hardware queue based ring buffer service between mgmt PF and PCIe hardware firmware for programming FPGA Program Logic, loading firmware and checking card healthy status. - programming FW - The base FW is downloaded onto the flash of the card. - The APU FW is downloaded once after a POR (power on reset). - Reloading the MgmtPF driver will not change any existing hardware. - programming FPGA hardware binaries - PL Data - using fpga framework ops to support re-programing FPGA - the re-programming request will be initiated from the existing UserPF driver only, and the MgmtPF driver load the matched PL Data after receiving request from the communication channel. The matching PL Data is indexed by the PL Data UUID and Base FW UUID. - The Base FW UUID identifies unique based hardware. Often called the interface UUID. - The PL Data UUID identifies unique PL design that is generated based on the base hardware. Often called xclbin UUID. - Example: 4fdebe35[...trimmed...]_96df7d[...trimmed...].xclbin | | | | +-- xclbin UUID --+ +--interface UUID --+ [1] https://github.com/Xilinx/XRT/blob/master/README.rst Co-developed-by: DMG Karthik Signed-off-by: DMG Karthik Co-developed-by: Nishad Saraf Signed-off-by: Nishad Saraf Co-developed-by: Prapul Krishnamurthy Signed-off-by: Prapul Krishnamurthy Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: Yidong Zhang --- MAINTAINERS | 6 + drivers/fpga/Kconfig | 3 + drivers/fpga/Makefile | 3 + drivers/fpga/amd/Kconfig | 15 ++ drivers/fpga/amd/Makefile | 5 + drivers/fpga/amd/versal-pci-main.c | 328 +++++++++++++++++++++++++++++ drivers/fpga/amd/versal-pci.h | 86 ++++++++ 7 files changed, 446 insertions(+) create mode 100644 drivers/fpga/amd/Kconfig create mode 100644 drivers/fpga/amd/Makefile create mode 100644 drivers/fpga/amd/versal-pci-main.c create mode 100644 drivers/fpga/amd/versal-pci.h diff --git a/MAINTAINERS b/MAINTAINERS index 17daa9ee9384..302c10004c5d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1194,6 +1194,12 @@ L: linux-spi@vger.kernel.org S: Supported F: drivers/spi/spi-amd.c +AMD VERSAL PCI DRIVER +M: Yidong Zhang +L: linux-fpga@vger.kernel.org +S: Supported +F: drivers/fpga/amd/ + AMD XGBE DRIVER M: "Shyam Sundar S K" L: netdev@vger.kernel.org diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 37b35f58f0df..dce060a7bd8f 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -290,4 +290,7 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI source "drivers/fpga/tests/Kconfig" +# Driver files +source "drivers/fpga/amd/Kconfig" + endif # FPGA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index aeb89bb13517..8412f3e211cc 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -58,5 +58,8 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o # Drivers for FPGAs which implement DFL obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o +# AMD PCIe Versal Management Driver +obj-$(CONFIG_AMD_VERSAL_PCI) += amd/ + # KUnit tests obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ diff --git a/drivers/fpga/amd/Kconfig b/drivers/fpga/amd/Kconfig new file mode 100644 index 000000000000..b18a42a340ba --- /dev/null +++ b/drivers/fpga/amd/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config AMD_VERSAL_PCI + tristate "AMD Versal PCIe Management Driver" + select FW_LOADER + select FW_UPLOAD + depends on FPGA + depends on HAS_IOMEM + depends on PCI + help + AMD Versal PCIe Management Driver provides management services to + download firmware, program bitstream, and communicate with the User + function. + + If "M" is selected, the driver module will be versal-pci diff --git a/drivers/fpga/amd/Makefile b/drivers/fpga/amd/Makefile new file mode 100644 index 000000000000..5d1ef04b5e80 --- /dev/null +++ b/drivers/fpga/amd/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_AMD_VERSAL_PCI) += versal-pci.o + +versal-pci-$(CONFIG_AMD_VERSAL_PCI) := versal-pci-main.o diff --git a/drivers/fpga/amd/versal-pci-main.c b/drivers/fpga/amd/versal-pci-main.c new file mode 100644 index 000000000000..a10ccf86802b --- /dev/null +++ b/drivers/fpga/amd/versal-pci-main.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Versal PCIe device + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + */ + +#include + +#include "versal-pci.h" + +#define DRV_NAME "amd-versal-pci" + +#define PCI_DEVICE_ID_V70PQ2 0x50B0 +#define VERSAL_XCLBIN_MAGIC_ID "xclbin2" + +static int versal_pci_fpga_write_init(struct fpga_manager *mgr, struct fpga_image_info *info, + const char *buf, size_t count) +{ + /* TODO */ + return 0; +} + +static int versal_pci_fpga_write(struct fpga_manager *mgr, const char *buf, + size_t count) +{ + /* TODO */ + return 0; +} + +static int versal_pci_fpga_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + /* TODO */ + return 0; +} + +static enum fpga_mgr_states versal_pci_fpga_state(struct fpga_manager *mgr) +{ + struct fpga_device *fdev = mgr->priv; + + return fdev->state; +} + +static const struct fpga_manager_ops versal_pci_fpga_ops = { + .write_init = versal_pci_fpga_write_init, + .write = versal_pci_fpga_write, + .write_complete = versal_pci_fpga_write_complete, + .state = versal_pci_fpga_state, +}; + +static void versal_pci_fpga_fini(struct fpga_device *fdev) +{ + fpga_mgr_unregister(fdev->mgr); +} + +static void versal_pci_uuid_parse(struct versal_pci_device *vdev, uuid_t *uuid) +{ + char str[UUID_STRING_LEN]; + u8 i, j; + + /* parse uuid into a valid uuid string format */ + for (i = 0, j = 0; i < strlen(vdev->fw_id) && i < sizeof(str); i++) { + str[j++] = vdev->fw_id[i]; + if (j == 8 || j == 13 || j == 18 || j == 23) + str[j++] = '-'; + } + + uuid_parse(str, uuid); + vdev_info(vdev, "Interface uuid %pU", uuid); +} + +static struct fpga_device *versal_pci_fpga_init(struct versal_pci_device *vdev) +{ + struct device *dev = &vdev->pdev->dev; + struct fpga_manager_info info = { 0 }; + struct fpga_device *fdev; + int ret; + + fdev = devm_kzalloc(dev, sizeof(*fdev), GFP_KERNEL); + if (!fdev) + return ERR_PTR(-ENOMEM); + + fdev->vdev = vdev; + + info = (struct fpga_manager_info) { + .name = "AMD Versal FPGA Manager", + .mops = &versal_pci_fpga_ops, + .priv = fdev, + }; + + fdev->mgr = fpga_mgr_register_full(dev, &info); + if (IS_ERR(fdev->mgr)) { + ret = PTR_ERR(fdev->mgr); + vdev_err(vdev, "Failed to register FPGA manager, err %d", ret); + return ERR_PTR(ret); + } + + /* Place holder for rm_queue_get_fw_id(vdev->rdev) */ + versal_pci_uuid_parse(vdev, &vdev->intf_uuid); + + return fdev; +} + +static int versal_pci_program_axlf(struct versal_pci_device *vdev, char *data, size_t size) +{ + const struct axlf *axlf = (struct axlf *)data; + struct fpga_image_info *image_info; + int ret; + + image_info = fpga_image_info_alloc(&vdev->pdev->dev); + if (!image_info) + return -ENOMEM; + + image_info->count = axlf->header.length; + image_info->buf = (char *)axlf; + + ret = fpga_mgr_load(vdev->fdev->mgr, image_info); + if (ret) { + vdev_err(vdev, "failed to load xclbin: %d", ret); + goto exit; + } + + vdev_info(vdev, "Downloaded axlf %pUb of size %zu Bytes", &axlf->header.uuid, size); + uuid_copy(&vdev->xclbin_uuid, &axlf->header.uuid); + +exit: + fpga_image_info_free(image_info); + + return ret; +} + +int versal_pci_load_xclbin(struct versal_pci_device *vdev, uuid_t *xuuid) +{ + const char *xclbin_location = "xilinx/xclbins"; + char fw_name[100]; + const struct firmware *fw; + int ret; + + snprintf(fw_name, sizeof(fw_name), "%s/%pUb_%s.xclbin", + xclbin_location, xuuid, vdev->fw_id); + + vdev_info(vdev, "trying to load %s", fw_name); + ret = request_firmware(&fw, fw_name, &vdev->pdev->dev); + if (ret) { + vdev_warn(vdev, "request xclbin fw %s failed %d", fw_name, ret); + return ret; + } + vdev_info(vdev, "loaded data size %zu", fw->size); + + ret = versal_pci_program_axlf(vdev, (char *)fw->data, fw->size); + if (ret) + vdev_err(vdev, "program axlf %s failed %d", fw_name, ret); + + release_firmware(fw); + + return ret; +} + +static enum fw_upload_err versal_pci_fw_prepare(struct fw_upload *fw_upload, const u8 *data, + u32 size) +{ + /* TODO */ + return FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err versal_pci_fw_write(struct fw_upload *fw_upload, const u8 *data, + u32 offset, u32 size, u32 *written) +{ + /* TODO */ + return FW_UPLOAD_ERR_NONE; +} + +static enum fw_upload_err versal_pci_fw_poll_complete(struct fw_upload *fw_upload) +{ + /* TODO */ + return FW_UPLOAD_ERR_NONE; +} + +static void versal_pci_fw_cancel(struct fw_upload *fw_upload) +{ + /* TODO */ +} + +static void versal_pci_fw_cleanup(struct fw_upload *fw_upload) +{ + /* TODO */ +} + +static const struct fw_upload_ops versal_pci_fw_ops = { + .prepare = versal_pci_fw_prepare, + .write = versal_pci_fw_write, + .poll_complete = versal_pci_fw_poll_complete, + .cancel = versal_pci_fw_cancel, + .cleanup = versal_pci_fw_cleanup, +}; + +static void versal_pci_fw_upload_fini(struct firmware_device *fwdev) +{ + firmware_upload_unregister(fwdev->fw); + kfree(fwdev->name); +} + +static u32 versal_pci_devid(struct versal_pci_device *vdev) +{ + return ((pci_domain_nr(vdev->pdev->bus) << 16) | + PCI_DEVID(vdev->pdev->bus->number, vdev->pdev->devfn)); +} + +static struct firmware_device *versal_pci_fw_upload_init(struct versal_pci_device *vdev) +{ + struct device *dev = &vdev->pdev->dev; + struct firmware_device *fwdev; + u32 devid; + + fwdev = devm_kzalloc(dev, sizeof(*fwdev), GFP_KERNEL); + if (!fwdev) + return ERR_PTR(-ENOMEM); + + devid = versal_pci_devid(vdev); + fwdev->name = kasprintf(GFP_KERNEL, "%s%x", DRV_NAME, devid); + if (!fwdev->name) + return ERR_PTR(-ENOMEM); + + fwdev->fw = firmware_upload_register(THIS_MODULE, dev, fwdev->name, + &versal_pci_fw_ops, fwdev); + if (IS_ERR(fwdev->fw)) { + kfree(fwdev->name); + return ERR_CAST(fwdev->fw); + } + + fwdev->vdev = vdev; + + return fwdev; +} + +static void versal_pci_device_teardown(struct versal_pci_device *vdev) +{ + versal_pci_fpga_fini(vdev->fdev); + versal_pci_fw_upload_fini(vdev->fwdev); +} + +static int versal_pci_device_setup(struct versal_pci_device *vdev) +{ + int ret; + + vdev->fwdev = versal_pci_fw_upload_init(vdev); + if (IS_ERR(vdev->fwdev)) { + ret = PTR_ERR(vdev->fwdev); + vdev_err(vdev, "Failed to init FW uploader, err %d", ret); + return ret; + } + + vdev->fdev = versal_pci_fpga_init(vdev); + if (IS_ERR(vdev->fdev)) { + ret = PTR_ERR(vdev->fdev); + vdev_err(vdev, "Failed to init FPGA manager, err %d", ret); + goto upload_fini; + } + + return 0; + +upload_fini: + versal_pci_fw_upload_fini(vdev->fwdev); + + return ret; +} + +static void versal_pci_remove(struct pci_dev *pdev) +{ + struct versal_pci_device *vdev = pci_get_drvdata(pdev); + + versal_pci_device_teardown(vdev); +} + +static int versal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) +{ + struct versal_pci_device *vdev; + int ret; + + vdev = devm_kzalloc(&pdev->dev, sizeof(*vdev), GFP_KERNEL); + if (!vdev) + return -ENOMEM; + + pci_set_drvdata(pdev, vdev); + vdev->pdev = pdev; + + ret = pcim_enable_device(pdev); + if (ret) { + vdev_err(vdev, "Failed to enable device %d", ret); + return ret; + } + + vdev->io_regs = pcim_iomap_region(vdev->pdev, MGMT_BAR, DRV_NAME); + if (IS_ERR(vdev->io_regs)) { + vdev_err(vdev, "Failed to map RM shared memory BAR%d", MGMT_BAR); + return PTR_ERR(vdev->io_regs); + } + + ret = versal_pci_device_setup(vdev); + if (ret) { + vdev_err(vdev, "Failed to setup Versal device %d", ret); + return ret; + } + + vdev_dbg(vdev, "Successfully probed %s driver!", DRV_NAME); + return 0; +} + +static const struct pci_device_id versal_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_V70PQ2), }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, versal_pci_ids); + +static struct pci_driver versal_pci_driver = { + .name = DRV_NAME, + .id_table = versal_pci_ids, + .probe = versal_pci_probe, + .remove = versal_pci_remove, +}; + +module_pci_driver(versal_pci_driver); + +MODULE_DESCRIPTION("AMD Versal PCIe Management Driver"); +MODULE_AUTHOR("XRT Team "); +MODULE_LICENSE("GPL"); diff --git a/drivers/fpga/amd/versal-pci.h b/drivers/fpga/amd/versal-pci.h new file mode 100644 index 000000000000..1509bd0532ea --- /dev/null +++ b/drivers/fpga/amd/versal-pci.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Driver for Versal PCIe device + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + */ + +#ifndef __VERSAL_PCI_H +#define __VERSAL_PCI_H + +#include +#include + +#define MGMT_BAR 0 + +#define vdev_info(vdev, fmt, args...) \ + dev_info(&(vdev)->pdev->dev, "%s: "fmt, __func__, ##args) + +#define vdev_warn(vdev, fmt, args...) \ + dev_warn(&(vdev)->pdev->dev, "%s: "fmt, __func__, ##args) + +#define vdev_err(vdev, fmt, args...) \ + dev_err(&(vdev)->pdev->dev, "%s: "fmt, __func__, ##args) + +#define vdev_dbg(vdev, fmt, args...) \ + dev_dbg(&(vdev)->pdev->dev, fmt, ##args) + +struct versal_pci_device; + +struct axlf_header { + __u64 length; + __u8 reserved1[24]; + uuid_t rom_uuid; + __u8 reserved2[64]; + uuid_t uuid; + __u8 reserved3[24]; +} __packed; + +struct axlf { + __u8 magic[8]; + __u8 reserved[296]; + struct axlf_header header; +} __packed; + +struct fw_tnx { + struct rm_cmd *cmd; + __u32 opcode; + __u32 id; +}; + +struct fpga_device { + enum fpga_mgr_states state; + struct fpga_manager *mgr; + struct versal_pci_device *vdev; + struct fw_tnx fw; +}; + +struct firmware_device { + struct versal_pci_device *vdev; + struct fw_upload *fw; + __u8 *name; + __u32 fw_name_id; + struct rm_cmd *cmd; + __u32 id; + uuid_t uuid; +}; + +struct versal_pci_device { + struct pci_dev *pdev; + + struct fpga_device *fdev; + struct firmware_device *fwdev; + struct device *device; + + void __iomem *io_regs; + uuid_t xclbin_uuid; + uuid_t intf_uuid; + __u8 fw_id[UUID_STRING_LEN + 1]; + + __u8 *debugfs_root; +}; + +/* versal pci driver APIs */ +int versal_pci_load_xclbin(struct versal_pci_device *vdev, uuid_t *xclbin_uuid); + +#endif /* __VERSAL_PCI_H */ From patchwork Tue Dec 10 18:37:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yidong Zhang X-Patchwork-Id: 13901915 Received: from NAM12-DM6-obe.outbound.protection.outlook.com (mail-dm6nam12on2041.outbound.protection.outlook.com [40.107.243.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9BF181BC9E2; Tue, 10 Dec 2024 18:37:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.243.41 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733855881; cv=fail; b=UcUGRHe8HxLkxvTnndF7V3IDJFS/pPNl2uUgIXvo24rR36C/Du8M0D1stEdRZMXofl05K4p0jILpIHScB9qy25qkx8qEbS08Xi/AQxy5m7qb7pWLyg5IlO2AQxY76BY8mHDfIyOGGQumCtd5OjlEC4uQ4Ih5rWfuEP7fFavkyLk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733855881; c=relaxed/simple; bh=6Yflc22+UMEVcJmTJQaSoVitwGFnbnLRelCa85EKric=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=B1PwXtSKYm68rLQs567j2hGKbsFkZAjkdfHF8bqQeIm/Quw3DN5apM62VugILRom9z72/b9iy3Hd6epHg500t/CsAabYmM/4valALzARo9J47snEBHTOCp6q8ZFosTgFIz+oDvd6rUosB83lzG02K2wwXgnCYEEFV1R7SsXCB0E= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=oQgPnx8j; arc=fail smtp.client-ip=40.107.243.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="oQgPnx8j" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=MI1/K/bhsMa7gakP0jKQlAO99XotfZecat899TiRgsTeftxdiP5QNSEqiEi2h8u8smYLpc7Nf1T2pSwctNwc9V+KVUuqC5aAOi//UJoi7hJhtzKuz3Hc4hEXxYSzQqfaKvFhN2vm1O4jwJMDqRWiPar5Wl0X9IaCDs/uDx+PJfdHdNPxETsAzuJ6FJxda5xAS0KfEf+oO8yqpgnMg6hhv2FZbxHmMlmz/Osji1tyEVBd2SF8L9qE+DRbAP2oZxtE7Kjk40Ptrw73QTd73P77T2wwtQZw8wLU7CGdea/oPse5OkmSc8tAfP4VEjU+8GzjPSfZTWhwctLyPujG7Ec74A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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; bh=UkfM8v07g4zhLjtk8O46Px533kZKqiKQTfxSSh3jbqA=; b=E4xszOQoOmkn4bnbTqyZpM6Wy6H/aIcoKj1xZr/ChO+8T0z9R/gheo3+xd7EEPVCle0pMs0ANcTg4Y77IbohRa4K1+6/4zMacJPP2yeHVvTGZNODTaPaacoQZkc8rkaprzTXz8TKTLcGdXMnCjsJfirXX3BGb7b2PDBv7I8NHZHGryIU3+/AXs1GIb1gTyV00CYzEj6jfKtcp78bM+pRyhem7+wG/aVKmhIiAVbmLzZYliu4fokm55i+03l3Dp/vT4NmphU3NM8Ai7R0iGvBhhWJEwCEa/Z27CV0031CaXN6uHIiECCaFe6ctixLyMO3oAMgsr39dK8eVsn4Xwe9gw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=UkfM8v07g4zhLjtk8O46Px533kZKqiKQTfxSSh3jbqA=; b=oQgPnx8j9B6kkvhre/3fk1EHyvakw22dPmJJQ9DsTz8nK+QxaI1otlzC2/qldXVZJU3qougFbd/81qmgknODmmg9u44bpvLz1xFW+p9FuQK2KMcSi3ciqcQKzpinCkFGHYDJi37HzUytGYG8UzuOg7E/rT+maCVIFhq5qS3fECg= Received: from CH2PR17CA0017.namprd17.prod.outlook.com (2603:10b6:610:53::27) by SA0PR12MB4496.namprd12.prod.outlook.com (2603:10b6:806:9b::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8230.18; Tue, 10 Dec 2024 18:37:55 +0000 Received: from DS2PEPF00003446.namprd04.prod.outlook.com (2603:10b6:610:53:cafe::21) by CH2PR17CA0017.outlook.office365.com (2603:10b6:610:53::27) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.8251.14 via Frontend Transport; Tue, 10 Dec 2024 18:37:55 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB03.amd.com; pr=C Received: from SATLEXMB03.amd.com (165.204.84.17) by DS2PEPF00003446.mail.protection.outlook.com (10.167.17.73) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.8230.7 via Frontend Transport; Tue, 10 Dec 2024 18:37:54 +0000 Received: from SATLEXMB06.amd.com (10.181.40.147) by SATLEXMB03.amd.com (10.181.40.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Tue, 10 Dec 2024 12:37:53 -0600 Received: from SATLEXMB03.amd.com (10.181.40.144) by SATLEXMB06.amd.com (10.181.40.147) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Tue, 10 Dec 2024 12:37:53 -0600 Received: from xsjyliu51.xilinx.com (10.180.168.240) by SATLEXMB03.amd.com (10.181.40.144) with Microsoft SMTP Server id 15.1.2507.39 via Frontend Transport; Tue, 10 Dec 2024 12:37:53 -0600 From: Yidong Zhang To: , , , , CC: Yidong Zhang , , Nishad Saraf Subject: [PATCH V2 2/4] drivers/fpga/amd: Add communication channel Date: Tue, 10 Dec 2024 10:37:31 -0800 Message-ID: <20241210183734.30803-3-yidong.zhang@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241210183734.30803-1-yidong.zhang@amd.com> References: <20241210183734.30803-1-yidong.zhang@amd.com> Precedence: bulk X-Mailing-List: linux-fpga@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DS2PEPF00003446:EE_|SA0PR12MB4496:EE_ X-MS-Office365-Filtering-Correlation-Id: 798de9e6-d6fc-4ac1-bb99-08dd1949c2e4 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|82310400026|1800799024|36860700013; X-Microsoft-Antispam-Message-Info: jUxGNSTkT/1RSajSAxb9MHH7PY+S+gXd9ei18HyOmSx/g9CW7Z3uAMIbZfOwdr1bKpnDiO8P9jXGsI730S4NG3X9fUeO6mhCLOLNrv0wRLjxxUOP9aykLVzdIKY1NWH9r6lcw9IbhadraLOaf2l2xLKpyT9Rs6MQVnUX8+qhQ9mzPVwW4uvK1KpAhY/UhA9p/4x2dJpW/EbDZuUa5/512VvpDtddA2xUf4Gcu9z1F5LZUhYughCrpYru/yXMh8dMyLq2mFObntXUFYINZ3xJAc3miNsPhU2qLPk7UIBwBY47TmuV8Hlrtx8h77oLxxTUVeItY6Rf/f/uwgbYnfa503J/HH9t5JIUorVh2T0Ywi6SxxXpejvl+ciBDoRuhimfYjm8DJgixsxtX/C8P4Ii+osFvjz5Df66uGbi3v7dg9B1/8gUaabIsJ51nLa2EWyeY0s2Ng1XY+GcbEPBWz0+a+HBvg7AjrC7C9g5dr6Qle5sRtABXjcMT1+v4ZS6XZpknhGJTsqxHAl9PT+Jw0oxRehFiVAFWa1c9djPwmX+7X8R5pjT1hHW3wl6d21AAd3z66ycR6vuwT6jNRuK6C14tLvmZE/bA8LcBThMlD8+800ED8vU+0vsb2Id+2lZKb/ctXCVTv6ATn8UHsIH/brmQwBcnrxIi984Cm1s+74KmGRxy2SlhLLpCbDNCl1hB6KXDUglmKVTZ2lGYEHTCHQnUH1KYED85AEzEOFcmwxcIzYdWMjQEKZgDkHZ0fS8KYivjKL6jW9kXtvoY+Wrru8nWvtzXkbGc8MZe803oepz6eCvQK9i5FZKeA/rbOL7nGGfTOui274dj4yczdNH55I5rkGgiv/BJYITqIVc5DK2rcuDR8+BhVU3pJFxlfx9bstBSYF6lv0cVRfYFcORWIiaqmQN+0IVRhHNAUW76oMTtRIV+ITIID5+9VreIbeQ4JF+Ab6VWNyIOwsm/FuVhaW3o8taN/Mxwqm7ck+0+Fdfl8VnXoTZOZa6tKJUQmF5EqMOcRXzJkTWwH5wT+1MrAiruxbUddrAvGtlNpgZcyd8mBp3asIOvknBVlN7pqK2lbmyZzDHI3I7bVWUE4LFlYolG9lnxuwaO2nodSVLSaAYm/TVLG0D56ERkTCVfk8PlNmckNdz2QYVbxgxabYFLziXfw/LF2ScH3YihSfkLjq9KcMDA6jCnoHYmPnOJbGEw9HG8seTS+q7hLK3rI+ubriKc5Sp90qsXtPb2e88Dbog6FF5DLwPzHbY5wQAbvKlmdNJ6r7fwH02wMFqnkedtZZu893EBkwPB74bYxa/G4GtGHTA8hJXMGfCug59t1myn4c16TwKExGL4jF2HtKQR2e4IiqLMSf+BwG5kuO2SSe7lOPR4Hda1sw354Gx7GtTsGqFhs0VuWx3G1O4Qm8p7JEhk7MtRv3z7mjeH0cNAHFwD2tkyutDtP6Z6cpTlwyG3Wdh X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:SATLEXMB03.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(376014)(82310400026)(1800799024)(36860700013);DIR:OUT;SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Dec 2024 18:37:54.8461 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 798de9e6-d6fc-4ac1-bb99-08dd1949c2e4 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB03.amd.com] X-MS-Exchange-CrossTenant-AuthSource: DS2PEPF00003446.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA0PR12MB4496 The communication channel (comm_chan) service is between versal-pci and the user PF driver. When the user PF driver requests PL data download, the comm_chan service will handle the request by versal_pci_load_xclbin. Co-developed-by: Nishad Saraf Signed-off-by: Nishad Saraf Signed-off-by: Yidong Zhang --- drivers/fpga/amd/Makefile | 3 +- drivers/fpga/amd/versal-pci-comm-chan.c | 271 ++++++++++++++++++++++++ drivers/fpga/amd/versal-pci-comm-chan.h | 14 ++ drivers/fpga/amd/versal-pci-main.c | 14 +- drivers/fpga/amd/versal-pci.h | 2 + 5 files changed, 301 insertions(+), 3 deletions(-) create mode 100644 drivers/fpga/amd/versal-pci-comm-chan.c create mode 100644 drivers/fpga/amd/versal-pci-comm-chan.h diff --git a/drivers/fpga/amd/Makefile b/drivers/fpga/amd/Makefile index 5d1ef04b5e80..7a604785e5f9 100644 --- a/drivers/fpga/amd/Makefile +++ b/drivers/fpga/amd/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_AMD_VERSAL_PCI) += versal-pci.o -versal-pci-$(CONFIG_AMD_VERSAL_PCI) := versal-pci-main.o +versal-pci-$(CONFIG_AMD_VERSAL_PCI) := versal-pci-main.o \ + versal-pci-comm-chan.o diff --git a/drivers/fpga/amd/versal-pci-comm-chan.c b/drivers/fpga/amd/versal-pci-comm-chan.c new file mode 100644 index 000000000000..20ccb1ac7754 --- /dev/null +++ b/drivers/fpga/amd/versal-pci-comm-chan.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Versal PCIe device + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + */ + +#include +#include + +#include "versal-pci.h" +#include "versal-pci-comm-chan.h" + +#define COMM_CHAN_PROTOCOL_VERSION 1 +#define COMM_CHAN_PCI_BAR_OFF 0x2000000 +#define COMM_CHAN_TIMER (HZ / 10) +#define COMM_CHAN_DATA_LEN 16 +#define COMM_CHAN_DATA_TYPE_MASK GENMASK(7, 0) +#define COMM_CHAN_DATA_EOM_MASK BIT(31) +#define COMM_CHAN_MSG_END BIT(31) + +#define COMM_CHAN_REG_WRDATA_OFF 0x0 +#define COMM_CHAN_REG_RDDATA_OFF 0x8 +#define COMM_CHAN_REG_STATUS_OFF 0x10 +#define COMM_CHAN_REG_ERROR_OFF 0x14 +#define COMM_CHAN_REG_RIT_OFF 0x1C +#define COMM_CHAN_REG_IS_OFF 0x20 +#define COMM_CHAN_REG_IE_OFF 0x24 +#define COMM_CHAN_REG_CTRL_OFF 0x2C +#define COMM_CHAN_REGS_SIZE SZ_4K + +#define COMM_CHAN_IRQ_DISABLE_ALL 0 +#define COMM_CHAN_IRQ_RECEIVE_ENABLE BIT(1) +#define COMM_CHAN_IRQ_CLEAR_ALL GENMASK(2, 0) +#define COMM_CHAN_CLEAR_FIFO GENMASK(1, 0) +#define COMM_CHAN_RECEIVE_THRESHOLD 15 + +enum comm_chan_req_ops { + COMM_CHAN_REQ_OPS_UNKNOWN = 0, + COMM_CHAN_REQ_OPS_HOT_RESET = 5, + COMM_CHAN_REQ_OPS_GET_PROTOCOL_VERSION = 19, + COMM_CHAN_REQ_OPS_LOAD_XCLBIN_UUID = 20, + COMM_CHAN_REQ_OPS_MAX, +}; + +enum comm_chan_msg_type { + COMM_CHAN_MSG_INVALID = 0, + COMM_CHAN_MSG_START = 2, + COMM_CHAN_MSG_BODY = 3, +}; + +enum comm_chan_msg_service_type { + COMM_CHAN_MSG_SRV_RESPONSE = BIT(0), + COMM_CHAN_MSG_SRV_REQUEST = BIT(1), +}; + +struct comm_chan_hw_msg { + struct { + __u32 type; + __u32 payload_size; + } header; + struct { + __u64 id; + __u32 flags; + __u32 size; + __u32 payload[COMM_CHAN_DATA_LEN - 6]; + } body; +} __packed; + +struct comm_chan_srv_req { + __u64 flags; + __u32 opcode; + __u32 data[]; +}; + +struct comm_chan_srv_ver_resp { + __u32 version; +}; + +struct comm_chan_srv_uuid_resp { + __u32 ret; +}; + +struct comm_chan_msg { + __u64 id; + __u32 flags; + __u32 len; + __u32 bytes_read; + __u32 data[10]; +}; + +struct comm_chan_device { + struct versal_pci_device *vdev; + struct timer_list timer; + struct work_struct work; +}; + +static inline struct comm_chan_device *to_ccdev_work(struct work_struct *w) +{ + return container_of(w, struct comm_chan_device, work); +} + +static inline struct comm_chan_device *to_ccdev_timer(struct timer_list *t) +{ + return container_of(t, struct comm_chan_device, timer); +} + +static inline u32 comm_chan_read(struct comm_chan_device *cdev, u32 offset) +{ + return readl(cdev->vdev->io_regs + COMM_CHAN_PCI_BAR_OFF + offset); +} + +static inline void comm_chan_write(struct comm_chan_device *cdev, u32 offset, const u32 value) +{ + writel(value, cdev->vdev->io_regs + COMM_CHAN_PCI_BAR_OFF + offset); +} + +static u32 comm_chan_set_uuid_resp(void *payload, int ret) +{ + struct comm_chan_srv_uuid_resp *resp = (struct comm_chan_srv_uuid_resp *)payload; + u32 resp_len = sizeof(*resp); + + resp->ret = (u32)ret; + + return resp_len; +} + +static u32 comm_chan_set_protocol_resp(void *payload) +{ + struct comm_chan_srv_ver_resp *resp = (struct comm_chan_srv_ver_resp *)payload; + u32 resp_len = sizeof(*resp); + + resp->version = COMM_CHAN_PROTOCOL_VERSION; + + return sizeof(resp_len); +} + +static void comm_chan_send_response(struct comm_chan_device *ccdev, u64 msg_id, void *payload) +{ + struct comm_chan_srv_req *req = (struct comm_chan_srv_req *)payload; + struct versal_pci_device *vdev = ccdev->vdev; + struct comm_chan_hw_msg response = {0}; + u32 size; + int ret; + u8 i; + + switch (req->opcode) { + case COMM_CHAN_REQ_OPS_GET_PROTOCOL_VERSION: + size = comm_chan_set_protocol_resp(response.body.payload); + break; + case COMM_CHAN_REQ_OPS_LOAD_XCLBIN_UUID: + ret = versal_pci_load_xclbin(vdev, (uuid_t *)req->data); + size = comm_chan_set_uuid_resp(response.body.payload, ret); + break; + default: + vdev_err(vdev, "Unsupported request opcode: %d", req->opcode); + *response.body.payload = -1; + size = sizeof(int); + } + + vdev_dbg(vdev, "Response opcode: %d", req->opcode); + + response.header.type = COMM_CHAN_MSG_START | COMM_CHAN_MSG_END; + response.header.payload_size = size; + + response.body.flags = COMM_CHAN_MSG_SRV_RESPONSE; + response.body.size = size; + response.body.id = msg_id; + + for (i = 0; i < COMM_CHAN_DATA_LEN; i++) + comm_chan_write(ccdev, COMM_CHAN_REG_WRDATA_OFF, ((u32 *)&response)[i]); +} + +#define STATUS_IS_READY(status) ((status) & BIT(1)) +#define STATUS_IS_ERROR(status) ((status) & BIT(2)) + +static void comm_chan_check_request(struct work_struct *w) +{ + struct comm_chan_device *ccdev = to_ccdev_work(w); + u32 status = 0, request[COMM_CHAN_DATA_LEN] = {0}; + struct comm_chan_hw_msg *hw_msg; + u8 type, eom; + int i; + + status = comm_chan_read(ccdev, COMM_CHAN_REG_IS_OFF); + if (!STATUS_IS_READY(status)) + return; + if (STATUS_IS_ERROR(status)) { + vdev_err(ccdev->vdev, "An error has occurred with comms"); + return; + } + + /* ACK status */ + comm_chan_write(ccdev, COMM_CHAN_REG_IS_OFF, status); + + for (i = 0; i < COMM_CHAN_DATA_LEN; i++) + request[i] = comm_chan_read(ccdev, COMM_CHAN_REG_RDDATA_OFF); + + hw_msg = (struct comm_chan_hw_msg *)request; + type = FIELD_GET(COMM_CHAN_DATA_TYPE_MASK, hw_msg->header.type); + eom = FIELD_GET(COMM_CHAN_DATA_EOM_MASK, hw_msg->header.type); + + /* Only support fixed size 64B messages */ + if (!eom || type != COMM_CHAN_MSG_START) { + vdev_err(ccdev->vdev, "Unsupported message format or length"); + return; + } + + if (hw_msg->body.flags != COMM_CHAN_MSG_SRV_REQUEST) { + vdev_err(ccdev->vdev, "Unsupported service request"); + return; + } + + if (hw_msg->body.size > sizeof(hw_msg->body.payload)) { + vdev_err(ccdev->vdev, "msg is too big: %d", hw_msg->body.size); + return; + } + + /* Now decode and respond appropriately */ + comm_chan_send_response(ccdev, hw_msg->body.id, hw_msg->body.payload); +} + +static void comm_chan_sched_work(struct timer_list *t) +{ + struct comm_chan_device *ccdev = to_ccdev_timer(t); + + /* Schedule a work in the general workqueue */ + schedule_work(&ccdev->work); + /* Periodic timer */ + mod_timer(&ccdev->timer, jiffies + COMM_CHAN_TIMER); +} + +static void comm_chan_config(struct comm_chan_device *ccdev) +{ + /* Disable interrupts */ + comm_chan_write(ccdev, COMM_CHAN_REG_IE_OFF, COMM_CHAN_IRQ_DISABLE_ALL); + /* Clear request and response FIFOs */ + comm_chan_write(ccdev, COMM_CHAN_REG_CTRL_OFF, COMM_CHAN_CLEAR_FIFO); + /* Clear interrupts */ + comm_chan_write(ccdev, COMM_CHAN_REG_IS_OFF, COMM_CHAN_IRQ_CLEAR_ALL); + /* Setup RIT reg */ + comm_chan_write(ccdev, COMM_CHAN_REG_RIT_OFF, COMM_CHAN_RECEIVE_THRESHOLD); + /* Enable RIT interrupt */ + comm_chan_write(ccdev, COMM_CHAN_REG_IE_OFF, COMM_CHAN_IRQ_RECEIVE_ENABLE); + + /* Create and schedule timer to do recurring work */ + INIT_WORK(&ccdev->work, &comm_chan_check_request); + timer_setup(&ccdev->timer, &comm_chan_sched_work, 0); + mod_timer(&ccdev->timer, jiffies + COMM_CHAN_TIMER); +} + +void versal_pci_comm_chan_fini(struct comm_chan_device *ccdev) +{ + /* First stop scheduling new work then cancel work */ + del_timer_sync(&ccdev->timer); + cancel_work_sync(&ccdev->work); +} + +struct comm_chan_device *versal_pci_comm_chan_init(struct versal_pci_device *vdev) +{ + struct comm_chan_device *ccdev; + + ccdev = devm_kzalloc(&vdev->pdev->dev, sizeof(*ccdev), GFP_KERNEL); + if (!ccdev) + return ERR_PTR(-ENOMEM); + + ccdev->vdev = vdev; + + comm_chan_config(ccdev); + return ccdev; +} diff --git a/drivers/fpga/amd/versal-pci-comm-chan.h b/drivers/fpga/amd/versal-pci-comm-chan.h new file mode 100644 index 000000000000..7605abc5527f --- /dev/null +++ b/drivers/fpga/amd/versal-pci-comm-chan.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Driver for Versal PCIe device + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + */ + +#ifndef __VERSAL_PCI_COMM_CHAN_H +#define __VERSAL_PCI_COMM_CHAN_H + +struct comm_chan_device *versal_pci_comm_chan_init(struct versal_pci_device *vdev); +void versal_pci_comm_chan_fini(struct comm_chan_device *ccdev); + +#endif /* __VERSAL_PCI_COMM_CHAN_H */ diff --git a/drivers/fpga/amd/versal-pci-main.c b/drivers/fpga/amd/versal-pci-main.c index a10ccf86802b..a3b83197c6d5 100644 --- a/drivers/fpga/amd/versal-pci-main.c +++ b/drivers/fpga/amd/versal-pci-main.c @@ -8,6 +8,7 @@ #include #include "versal-pci.h" +#include "versal-pci-comm-chan.h" #define DRV_NAME "amd-versal-pci" @@ -238,6 +239,7 @@ static void versal_pci_device_teardown(struct versal_pci_device *vdev) { versal_pci_fpga_fini(vdev->fdev); versal_pci_fw_upload_fini(vdev->fwdev); + versal_pci_comm_chan_fini(vdev->ccdev); } static int versal_pci_device_setup(struct versal_pci_device *vdev) @@ -251,15 +253,23 @@ static int versal_pci_device_setup(struct versal_pci_device *vdev) return ret; } + vdev->ccdev = versal_pci_comm_chan_init(vdev); + if (IS_ERR(vdev->ccdev)) { + ret = PTR_ERR(vdev->ccdev); + vdev_err(vdev, "Failed to init comms channel, err %d", ret); + goto upload_fini; + } + vdev->fdev = versal_pci_fpga_init(vdev); if (IS_ERR(vdev->fdev)) { ret = PTR_ERR(vdev->fdev); vdev_err(vdev, "Failed to init FPGA manager, err %d", ret); - goto upload_fini; + goto comm_chan_fini; } return 0; - +comm_chan_fini: + versal_pci_comm_chan_fini(vdev->ccdev); upload_fini: versal_pci_fw_upload_fini(vdev->fwdev); diff --git a/drivers/fpga/amd/versal-pci.h b/drivers/fpga/amd/versal-pci.h index 1509bd0532ea..6c1ca3ce505d 100644 --- a/drivers/fpga/amd/versal-pci.h +++ b/drivers/fpga/amd/versal-pci.h @@ -26,6 +26,7 @@ dev_dbg(&(vdev)->pdev->dev, fmt, ##args) struct versal_pci_device; +struct comm_chan_device; struct axlf_header { __u64 length; @@ -69,6 +70,7 @@ struct versal_pci_device { struct pci_dev *pdev; struct fpga_device *fdev; + struct comm_chan_device *ccdev; struct firmware_device *fwdev; struct device *device; From patchwork Tue Dec 10 18:37:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yidong Zhang X-Patchwork-Id: 13901918 Received: from NAM10-DM6-obe.outbound.protection.outlook.com (mail-dm6nam10on2059.outbound.protection.outlook.com [40.107.93.59]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80A99214223; Tue, 10 Dec 2024 18:38:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.93.59 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733855889; cv=fail; b=n8HNzqKhkJp4wXOtZjIwsn4SEMEmxfKEELBCFKCl+pmPSky+VBFh9ofFAFeRe6lCaYo/xNZuPl0g8QPVDYr+/kv8ZOU1KfXXrwPEMSPDUEqr66b3/GFouDqUpSGEJPmaOBCHtx5MKA7EMDQglLsIszkBg6U0Qh7tPItKPR6sjCU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733855889; c=relaxed/simple; bh=NQIoY+oXM7XOjyafjY385stot4bZGPgTl0EVpVOevtM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ihTb6n5b38nDt4j7cARKYInc0YU7xb8l07vx91Wy9CdQOblnkQ+1TsaWeGUJyBudYJux8vtd5WQ0yLuJqY5Qz42FcQCtdKkPaNyoQJrsX/oNkTjLvk9Xb4/7ZFoDkDq1h8lq14afIhgX0ejBO1pgiwvxDBITlerMpFxqB+4eppE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=zLZZbg1t; arc=fail smtp.client-ip=40.107.93.59 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="zLZZbg1t" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=x9eIGp0AqK+VDcMNV92tfZpKocXva4y82N6+aMnNzos/JdfJfjMegeAlBqcHV6tjOCugaheWspZ7CR5/jjDM4+AclIUsbdJUYOsYvZOCqVEMc2jWmZCSdFz9BIlQMTInVp1MZYU4r6e5+b4PScEyP/2SeBD8YfDz97AVscXtv9GsPddy8nvR7v91Fj1mh7yX+gtY2ueWr+M72wZqJv+KiEXId4GxhPDgDvqePdDWdJtSD8m5BroLUUJ/tHgvIaMeoqtlVm7D/Xx1rIIHMLkmEfhc8oTZG0Nd456C3uSRLLEMPiUYASQbND3z+iC9oQX6SUwuS/PBu33VoqM3OXcK3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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; bh=8sVGtZZ9ZMm2oxW+LxmXFAa19cNChqImO4EO9fS0ElQ=; b=J0kW4mEI6d9iV0RBG34iXDEzHCl3sSOs6CuccEiiEBQT4/u5nWdCrmyr44L7OreJ9UMY2KuY+ym7XbOFrXshFMDC7EqmxTX+8fEzK0BHAcFmZWr2WzXT/XmeIDDQrl1y+97OeNXcCgmi+draPnHLElM8zGpToKgG0V/CpNNo6JCKXkSaM843ZYQIeN6si0y8Gj+aI+HeoS82soidf16I7sjQc0OcU4AY/iJLcYGhNY5+C4RIvlhCLUIUOMiTFf6FxEuOrpZQaK3iRd8kJIAqHh71iH5BdobyNQrxtO8XkIwTA4V6xzIFfHmfx3WpKTeJcKlroxSGPPtC+sMBPMTPAg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=8sVGtZZ9ZMm2oxW+LxmXFAa19cNChqImO4EO9fS0ElQ=; b=zLZZbg1t3J2MNFgHA6uveRDj3uFDvKRoj7SJzElA/NEBZI5ABs3CMqgjsskQ+YABIK/UWgLeePB1YJluAsfu3jpAYMKlyMwbw9iB2o6NADfsndvdRWZjaqk5ilj5QufmoBUzmPbRikDTrv2vTikKoMfHz2qs0ksFds9/Ug5zWeo= Received: from PH7P221CA0026.NAMP221.PROD.OUTLOOK.COM (2603:10b6:510:32a::21) by SN7PR12MB7129.namprd12.prod.outlook.com (2603:10b6:806:2a1::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8230.18; Tue, 10 Dec 2024 18:37:56 +0000 Received: from SN1PEPF000252A2.namprd05.prod.outlook.com (2603:10b6:510:32a:cafe::ac) by PH7P221CA0026.outlook.office365.com (2603:10b6:510:32a::21) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.8230.17 via Frontend Transport; Tue, 10 Dec 2024 18:37:56 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C Received: from SATLEXMB04.amd.com (165.204.84.17) by SN1PEPF000252A2.mail.protection.outlook.com (10.167.242.9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.8230.7 via Frontend Transport; Tue, 10 Dec 2024 18:37:55 +0000 Received: from SATLEXMB05.amd.com (10.181.40.146) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Tue, 10 Dec 2024 12:37:54 -0600 Received: from SATLEXMB03.amd.com (10.181.40.144) by SATLEXMB05.amd.com (10.181.40.146) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Tue, 10 Dec 2024 12:37:54 -0600 Received: from xsjyliu51.xilinx.com (10.180.168.240) by SATLEXMB03.amd.com (10.181.40.144) with Microsoft SMTP Server id 15.1.2507.39 via Frontend Transport; Tue, 10 Dec 2024 12:37:53 -0600 From: Yidong Zhang To: , , , , CC: Yidong Zhang , , Nishad Saraf , Prapul Krishnamurthy Subject: [PATCH V2 3/4] drivers/fpga/amd: Add remote queue Date: Tue, 10 Dec 2024 10:37:32 -0800 Message-ID: <20241210183734.30803-4-yidong.zhang@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241210183734.30803-1-yidong.zhang@amd.com> References: <20241210183734.30803-1-yidong.zhang@amd.com> Precedence: bulk X-Mailing-List: linux-fpga@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Received-SPF: None (SATLEXMB05.amd.com: yidong.zhang@amd.com does not designate permitted sender hosts) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SN1PEPF000252A2:EE_|SN7PR12MB7129:EE_ X-MS-Office365-Filtering-Correlation-Id: 7701de1a-0e82-4637-f9e1-08dd1949c37c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|376014|1800799024|36860700013; X-Microsoft-Antispam-Message-Info: tNz/bMTKGwJqJni1P5ftLQo4RPNubS8AjOqmDt6FyJNsA1YS9HOFfc/IQH47qaEvIzAVRaWIpNcx8Pjar68LTlMmu5lOnYqB9sVTD8qIC8mLioVDbiel6znL7OI7H3azZziwrTxfcSCiyNDf844V5pfv24SKIc2e880AWNbGB8OliXsZ/DpefiIRfmTqAHdK+rihkoMkJZ8sE3ChKg5R3As5PkZEDzXvOew6xkGhvAG+9LqM3iTWo0Dif8PQJ51pODKFZ5tK9oY6gAMVJAPzSLvij+vhaDl4gqu1mSm9mq5QabG7wHjClBPTpe3QxfZBJPoYGo3rkiort1hVkkxpWQAYTrk6qxD39iXiimofp4a7/4pcsf9T91G9ICeOGmkB46bRmspMWv0C5+rgEbjwvDCT5Jm7TyfM7jb+dbc+Y4L0GGBAc2fmPQ7vdbkqj19ZKyrqP7JWsDgDW8z+eWU2e8VzfEeSrYTVHDePGUMSm4/ltCvK381BhPP83iqOjMJySkIMTK3ZCAZFxQse6xxHyrZg7dQj6piA27G9+gBHl6g6n/diAbpqcnv6ssso/J5KeSC1weDv3kt2jBJZP85VslCwIYKXY9M1oa0Adwwt+vDKglZpHYTv/gzuEAUq7q41MWRQooLFxqCDdjBaeYobdUD6h9Fp16fUMr/jxSM2LxTESaJ0Pvl65GvZJ4Gf1mIo1kVwQZkn1NPmSq8zXV1skJz86fFblgphDmkoOLy2gBAr/ib54a4grljDTKO/a1KYLuFiVY2sgUf+0pSheFRg9RKrEGIGfdwVZKzkmXBx2eLNkU89P0sO30IdnrXuU982yPRIsj/oYDG0cohWOyA+SXd0pLwVOiOPSMyILVIyqdG3OsFulT6gxqGq0oEL61C8MC/Aa/zHe1dDEvydp50tbqM7WKYOBTSwlrJdXB1Vz9Jk/jczERjvF+EYXRsZ1sM5hG1XclDmlvvJ7F019RYlWeS3DX/7SGIk6Ic58wl+7sa3tBWbW3afJ5jOn0OWA6COFNk9e2dB/qILcbqJTehSWU9vmxPe7a508OJeszvPvC/FrPiRyXqD8p7E5p0P+RPeJG267XYgyaCFSgjc2BkgbXc9AAZda7eu/BgNXO7MSElbCU7twI3r8PexykyL7tpEqUSsV7ZovXwQTGfy7VOPvHmJwdW7TDtEvfiqpO5+HHMcQaxiQUdW0qqEBVqJIfEgxDh8dQPgdaWdOq7LlPCnyohh2YBzWNNFSOUwefHTYqqdjRSOwENIbNxe5duEw9c1PY8aG0Mfys2YxnEcwMiNQg3HuU633+r/ItDr6+bKkYSGwxHj9jjF6FLBLYJg2ExdeoRjFS0s+uzoN1cBIMtHd+lnwdUJ3377SfJAK9w8Jx3wF8PMhwly82W0r9z1h/z9TNt1RbtrZCLTsflL3K/VBZfDDFMsIXixiRJTKVF1c4wQYlmz2MPlR9LVjg+kM6eY X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:SATLEXMB04.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(82310400026)(376014)(1800799024)(36860700013);DIR:OUT;SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Dec 2024 18:37:55.8751 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7701de1a-0e82-4637-f9e1-08dd1949c37c X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: SN1PEPF000252A2.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN7PR12MB7129 The remote queue is a hardware queue based ring buffer service between mgmt PF and PCIe hardware firmware for programming FPGA Program Logic, loading versal firmware and checking card healthy status. Co-developed-by: Nishad Saraf Signed-off-by: Nishad Saraf Co-developed-by: Prapul Krishnamurthy Signed-off-by: Prapul Krishnamurthy Signed-off-by: Yidong Zhang --- drivers/fpga/amd/Makefile | 3 +- drivers/fpga/amd/versal-pci-rm-queue.c | 326 +++++++++++++++++++++++ drivers/fpga/amd/versal-pci-rm-queue.h | 21 ++ drivers/fpga/amd/versal-pci-rm-service.h | 209 +++++++++++++++ 4 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 drivers/fpga/amd/versal-pci-rm-queue.c create mode 100644 drivers/fpga/amd/versal-pci-rm-queue.h create mode 100644 drivers/fpga/amd/versal-pci-rm-service.h diff --git a/drivers/fpga/amd/Makefile b/drivers/fpga/amd/Makefile index 7a604785e5f9..b2ffdbf23400 100644 --- a/drivers/fpga/amd/Makefile +++ b/drivers/fpga/amd/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_AMD_VERSAL_PCI) += versal-pci.o versal-pci-$(CONFIG_AMD_VERSAL_PCI) := versal-pci-main.o \ - versal-pci-comm-chan.o + versal-pci-comm-chan.o \ + versal-pci-rm-queue.o diff --git a/drivers/fpga/amd/versal-pci-rm-queue.c b/drivers/fpga/amd/versal-pci-rm-queue.c new file mode 100644 index 000000000000..92f2e1165052 --- /dev/null +++ b/drivers/fpga/amd/versal-pci-rm-queue.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Versal PCIe device + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + */ + +#include + +#include "versal-pci.h" +#include "versal-pci-rm-queue.h" +#include "versal-pci-rm-service.h" + +static inline struct rm_device *to_rdev_msg_monitor(struct work_struct *w) +{ + return container_of(w, struct rm_device, msg_monitor); +} + +static inline struct rm_device *to_rdev_msg_timer(struct timer_list *t) +{ + return container_of(t, struct rm_device, msg_timer); +} + +static inline u32 rm_io_read(struct rm_device *rdev, u32 offset) +{ + /* TODO */ + return 0; +} + +static inline int rm_io_write(struct rm_device *rdev, u32 offset, u32 value) +{ + /* TODO */ + return 0; +} + +static inline u32 rm_queue_read(struct rm_device *rdev, u32 offset) +{ + /* TODO */ + return 0; +} + +static inline void rm_queue_write(struct rm_device *rdev, u32 offset, u32 value) +{ + /* TODO */ +} + +static inline void rm_queue_bulk_read(struct rm_device *rdev, u32 offset, + u32 *value, u32 size) +{ + /* TODO */ +} + +static inline void rm_queue_bulk_write(struct rm_device *rdev, u32 offset, + u32 *value, u32 size) +{ + /* TODO */ +} + +static inline u32 rm_queue_get_cidx(struct rm_device *rdev, enum rm_queue_type type) +{ + u32 off; + + if (type == RM_QUEUE_SQ) + off = offsetof(struct rm_queue_header, sq_cidx); + else + off = offsetof(struct rm_queue_header, cq_cidx); + + return rm_queue_read(rdev, off); +} + +static inline void rm_queue_set_cidx(struct rm_device *rdev, enum rm_queue_type type, + u32 value) +{ + u32 off; + + if (type == RM_QUEUE_SQ) + off = offsetof(struct rm_queue_header, sq_cidx); + else + off = offsetof(struct rm_queue_header, cq_cidx); + + rm_queue_write(rdev, off, value); +} + +static inline u32 rm_queue_get_pidx(struct rm_device *rdev, enum rm_queue_type type) +{ + if (type == RM_QUEUE_SQ) + return rm_io_read(rdev, RM_IO_SQ_PIDX_OFF); + else + return rm_io_read(rdev, RM_IO_CQ_PIDX_OFF); +} + +static inline int rm_queue_set_pidx(struct rm_device *rdev, + enum rm_queue_type type, u32 value) +{ + if (type == RM_QUEUE_SQ) + return rm_io_write(rdev, RM_IO_SQ_PIDX_OFF, value); + else + return rm_io_write(rdev, RM_IO_CQ_PIDX_OFF, value); +} + +static inline u32 rm_queue_get_sq_slot_offset(struct rm_device *rdev) +{ + u32 index; + + if ((rdev->sq.pidx - rdev->sq.cidx) >= rdev->queue_size) + return RM_INVALID_SLOT; + + index = rdev->sq.pidx & (rdev->queue_size - 1); + return rdev->sq.offset + RM_CMD_SQ_SLOT_SIZE * index; +} + +static inline u32 rm_queue_get_cq_slot_offset(struct rm_device *rdev) +{ + u32 index; + + index = rdev->cq.cidx & (rdev->queue_size - 1); + return rdev->cq.offset + RM_CMD_CQ_SLOT_SIZE * index; +} + +static int rm_queue_submit_cmd(struct rm_cmd *cmd) +{ + struct versal_pci_device *vdev = cmd->rdev->vdev; + struct rm_device *rdev = cmd->rdev; + u32 offset; + int ret; + + mutex_lock(&rdev->queue); + + offset = rm_queue_get_sq_slot_offset(rdev); + if (!offset) { + vdev_err(vdev, "No SQ slot available"); + ret = -ENOSPC; + goto exit; + } + + rm_queue_bulk_write(rdev, offset, (u32 *)&cmd->sq_msg, + sizeof(cmd->sq_msg)); + + ret = rm_queue_set_pidx(rdev, RM_QUEUE_SQ, ++rdev->sq.pidx); + if (ret) { + vdev_err(vdev, "Failed to update PIDX, ret %d", ret); + goto exit; + } + + list_add_tail(&cmd->list, &rdev->submitted_cmds); +exit: + mutex_unlock(&rdev->queue); + return ret; +} + +void rm_queue_withdraw_cmd(struct rm_cmd *cmd) +{ + mutex_lock(&cmd->rdev->queue); + list_del(&cmd->list); + mutex_unlock(&cmd->rdev->queue); +} + +static int rm_queue_wait_cmd_timeout(struct rm_cmd *cmd, unsigned long timeout) +{ + struct versal_pci_device *vdev = cmd->rdev->vdev; + int ret; + + if (wait_for_completion_timeout(&cmd->executed, timeout)) { + ret = cmd->cq_msg.data.rcode; + if (!ret) + return 0; + + vdev_err(vdev, "CMD returned with a failure: %d", ret); + return ret; + } + + /* + * each cmds will be cleaned up by complete before it times out. + * if we reach here, the cmd should be cleared and hot reset should + * be issued. + */ + vdev_err(vdev, "cmd is timedout after, please reset the card"); + rm_queue_withdraw_cmd(cmd); + return -ETIME; +} + +int rm_queue_send_cmd(struct rm_cmd *cmd, unsigned long timeout) +{ + int ret; + + ret = rm_queue_submit_cmd(cmd); + if (ret) + return ret; + + return rm_queue_wait_cmd_timeout(cmd, timeout); +} + +static int rm_process_msg(struct rm_device *rdev) +{ + struct versal_pci_device *vdev = rdev->vdev; + struct rm_cmd *cmd, *next; + struct rm_cmd_cq_hdr header; + u32 offset; + + offset = rm_queue_get_cq_slot_offset(rdev); + if (!offset) { + vdev_err(vdev, "Invalid CQ offset"); + return -EINVAL; + } + + rm_queue_bulk_read(rdev, offset, (u32 *)&header, sizeof(header)); + + list_for_each_entry_safe(cmd, next, &rdev->submitted_cmds, list) { + u32 value = 0; + + if (cmd->sq_msg.hdr.id != header.id) + continue; + + rm_queue_bulk_read(rdev, offset + sizeof(cmd->cq_msg.hdr), + (u32 *)&cmd->cq_msg.data, + sizeof(cmd->cq_msg.data)); + + rm_queue_write(rdev, offset, value); + + list_del(&cmd->list); + complete(&cmd->executed); + return 0; + } + + vdev_err(vdev, "Unknown cmd ID %d found in CQ", header.id); + return -EFAULT; +} + +static void rm_check_msg(struct work_struct *w) +{ + struct rm_device *rdev = to_rdev_msg_monitor(w); + int ret; + + mutex_lock(&rdev->queue); + + rdev->sq.cidx = rm_queue_get_cidx(rdev, RM_QUEUE_SQ); + rdev->cq.pidx = rm_queue_get_pidx(rdev, RM_QUEUE_CQ); + + while (rdev->cq.cidx < rdev->cq.pidx) { + ret = rm_process_msg(rdev); + if (ret) + break; + + rdev->cq.cidx++; + + rm_queue_set_cidx(rdev, RM_QUEUE_CQ, rdev->cq.cidx); + } + + mutex_unlock(&rdev->queue); +} + +static void rm_sched_work(struct timer_list *t) +{ + struct rm_device *rdev = to_rdev_msg_timer(t); + + /* Schedule a work in the general workqueue */ + schedule_work(&rdev->msg_monitor); + /* Periodic timer */ + mod_timer(&rdev->msg_timer, jiffies + RM_COMPLETION_TIMER); +} + +void rm_queue_fini(struct rm_device *rdev) +{ + del_timer_sync(&rdev->msg_timer); + cancel_work_sync(&rdev->msg_monitor); + mutex_destroy(&rdev->queue); +} + +int rm_queue_init(struct rm_device *rdev) +{ + struct versal_pci_device *vdev = rdev->vdev; + struct rm_queue_header header = {0}; + int ret; + + INIT_LIST_HEAD(&rdev->submitted_cmds); + mutex_init(&rdev->queue); + + rm_queue_bulk_read(rdev, RM_HDR_OFF, (u32 *)&header, sizeof(header)); + + if (header.magic != RM_QUEUE_HDR_MAGIC_NUM) { + vdev_err(vdev, "Invalid RM queue header"); + ret = -ENODEV; + goto error; + } + + if (!header.version) { + vdev_err(vdev, "Invalid RM queue header"); + ret = -ENODEV; + goto error; + } + + sema_init(&rdev->sq.data_lock, 1); + sema_init(&rdev->cq.data_lock, 1); + rdev->queue_size = header.size; + rdev->sq.offset = header.sq_off; + rdev->cq.offset = header.cq_off; + rdev->sq.type = RM_QUEUE_SQ; + rdev->cq.type = RM_QUEUE_CQ; + rdev->sq.data_size = rdev->queue_buffer_size - RM_CMD_CQ_BUFFER_SIZE; + rdev->cq.data_size = RM_CMD_CQ_BUFFER_SIZE; + rdev->sq.data_offset = rdev->queue_buffer_start + + RM_CMD_CQ_BUFFER_OFFSET + RM_CMD_CQ_BUFFER_SIZE; + rdev->cq.data_offset = rdev->queue_buffer_start + + RM_CMD_CQ_BUFFER_OFFSET; + rdev->sq.cidx = header.sq_cidx; + rdev->cq.cidx = header.cq_cidx; + + rdev->sq.pidx = rm_queue_get_pidx(rdev, RM_QUEUE_SQ); + rdev->cq.pidx = rm_queue_get_pidx(rdev, RM_QUEUE_CQ); + + if (rdev->cq.cidx != rdev->cq.pidx) { + vdev_warn(vdev, "Clearing stale completions"); + rdev->cq.cidx = rdev->cq.pidx; + rm_queue_set_cidx(rdev, RM_QUEUE_CQ, rdev->cq.cidx); + } + + /* Create and schedule timer to do recurring work */ + INIT_WORK(&rdev->msg_monitor, &rm_check_msg); + timer_setup(&rdev->msg_timer, &rm_sched_work, 0); + mod_timer(&rdev->msg_timer, jiffies + RM_COMPLETION_TIMER); + + return 0; +error: + mutex_destroy(&rdev->queue); + return ret; +} diff --git a/drivers/fpga/amd/versal-pci-rm-queue.h b/drivers/fpga/amd/versal-pci-rm-queue.h new file mode 100644 index 000000000000..3bc7102c6a58 --- /dev/null +++ b/drivers/fpga/amd/versal-pci-rm-queue.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Driver for Versal PCIe device + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + */ + +#ifndef __RM_QUEUE_H +#define __RM_QUEUE_H + +struct rm_device; + +/* rm queue hardware setup */ +int rm_queue_init(struct rm_device *rdev); +void rm_queue_fini(struct rm_device *rdev); + +/* rm queue common API */ +int rm_queue_send_cmd(struct rm_cmd *cmd, unsigned long timeout); +void rm_queue_withdraw_cmd(struct rm_cmd *cmd); + +#endif /* __RM_QUEUE_H */ diff --git a/drivers/fpga/amd/versal-pci-rm-service.h b/drivers/fpga/amd/versal-pci-rm-service.h new file mode 100644 index 000000000000..85a78257770a --- /dev/null +++ b/drivers/fpga/amd/versal-pci-rm-service.h @@ -0,0 +1,209 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Driver for Versal PCIe device + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + */ + +#ifndef __RM_SERVICE_H +#define __RM_SERVICE_H + +#define RM_HDR_OFF 0x0 +#define RM_HDR_MAGIC_NUM 0x564D5230 +#define RM_QUEUE_HDR_MAGIC_NUM 0x5847513F +#define RM_PCI_IO_BAR_OFF 0x2010000 +#define RM_PCI_IO_SIZE SZ_4K +#define RM_PCI_SHMEM_BAR_OFF 0x8000000 +#define RM_PCI_SHMEM_SIZE SZ_128M +#define RM_PCI_SHMEM_HDR_SIZE 0x28 + +#define RM_QUEUE_HDR_MAGIC_NUM_OFF 0x0 +#define RM_IO_SQ_PIDX_OFF 0x0 +#define RM_IO_CQ_PIDX_OFF 0x100 + +#define RM_CMD_ID_MIN 1 +#define RM_CMD_ID_MAX (BIT(17) - 1) +#define RM_CMD_SQ_HDR_OPS_MSK GENMASK(15, 0) +#define RM_CMD_SQ_HDR_SIZE_MSK GENMASK(14, 0) +#define RM_CMD_SQ_SLOT_SIZE SZ_512 +#define RM_CMD_CQ_SLOT_SIZE SZ_16 +#define RM_CMD_CQ_BUFFER_SIZE (1024 * 1024) +#define RM_CMD_CQ_BUFFER_OFFSET 0x0 +#define RM_CMD_LOG_PAGE_TYPE_MASK GENMASK(15, 0) +#define RM_CMD_VMR_CONTROL_MSK GENMASK(10, 8) +#define RM_CMD_VMR_CONTROL_PS_MASK BIT(9) + +#define RM_CMD_WAIT_CONFIG_TIMEOUT msecs_to_jiffies(10 * 1000) +#define RM_CMD_WAIT_DOWNLOAD_TIMEOUT msecs_to_jiffies(300 * 1000) + +#define RM_COMPLETION_TIMER (HZ / 10) +#define RM_HEALTH_CHECK_TIMER (HZ) + +#define RM_INVALID_SLOT 0 + +enum rm_queue_opcode { + RM_QUEUE_OP_LOAD_XCLBIN = 0x0, + RM_QUEUE_OP_GET_LOG_PAGE = 0x8, + RM_QUEUE_OP_LOAD_FW = 0xA, + RM_QUEUE_OP_LOAD_APU_FW = 0xD, + RM_QUEUE_OP_VMR_CONTROL = 0xE, + RM_QUEUE_OP_IDENTIFY = 0x202, +}; + +struct rm_cmd_sq_hdr { + __u16 opcode; + __u16 msg_size; + __u16 id; + __u16 reserved; +} __packed; + +struct rm_cmd_cq_hdr { + __u16 id; + __u16 reserved; +} __packed; + +struct rm_cmd_sq_bin { + __u64 address; + __u32 size; + __u32 reserved1; + __u32 reserved2; + __u32 reserved3; + __u64 reserved4; +} __packed; + +struct rm_cmd_sq_log_page { + __u64 address; + __u32 size; + __u32 reserved1; + __u32 type; + __u32 reserved2; +} __packed; + +struct rm_cmd_sq_ctrl { + __u32 status; +} __packed; + +struct rm_cmd_sq_data { + union { + struct rm_cmd_sq_log_page page; + struct rm_cmd_sq_bin bin; + struct rm_cmd_sq_ctrl ctrl; + }; +} __packed; + +struct rm_cmd_cq_identify { + __u16 major; + __u16 minor; + __u32 reserved; +} __packed; + +struct rm_cmd_cq_log_page { + __u32 len; + __u32 reserved; +} __packed; + +struct rm_cmd_cq_control { + __u16 status; + __u16 reserved1; + __u32 reserved2; +} __packed; + +struct rm_cmd_cq_data { + union { + struct rm_cmd_cq_identify identify; + struct rm_cmd_cq_log_page page; + struct rm_cmd_cq_control ctrl; + __u32 reserved[2]; + }; + __u32 rcode; +} __packed; + +struct rm_cmd_sq_msg { + struct rm_cmd_sq_hdr hdr; + struct rm_cmd_sq_data data; +} __packed; + +struct rm_cmd_cq_msg { + struct rm_cmd_cq_hdr hdr; + struct rm_cmd_cq_data data; +} __packed; + +struct rm_cmd { + struct rm_device *rdev; + struct list_head list; + struct completion executed; + struct rm_cmd_sq_msg sq_msg; + struct rm_cmd_cq_msg cq_msg; + enum rm_queue_opcode opcode; + __u8 *buffer; + ssize_t size; +}; + +enum rm_queue_type { + RM_QUEUE_SQ, + RM_QUEUE_CQ +}; + +enum rm_cmd_log_page_type { + RM_CMD_LOG_PAGE_AXI_TRIP_STATUS = 0x0, + RM_CMD_LOG_PAGE_FW_ID = 0xA, +}; + +struct rm_queue { + enum rm_queue_type type; + __u32 pidx; + __u32 cidx; + __u32 offset; + __u32 data_offset; + __u32 data_size; + struct semaphore data_lock; +}; + +struct rm_queue_header { + __u32 magic; + __u32 version; + __u32 size; + __u32 sq_off; + __u32 sq_slot_size; + __u32 cq_off; + __u32 sq_cidx; + __u32 cq_cidx; +}; + +struct rm_header { + __u32 magic; + __u32 queue_base; + __u32 queue_size; + __u32 status_off; + __u32 status_len; + __u32 log_index; + __u32 log_off; + __u32 log_size; + __u32 data_start; + __u32 data_end; +}; + +struct rm_device { + struct versal_pci_device *vdev; + + struct rm_header rm_metadata; + __u32 queue_buffer_start; + __u32 queue_buffer_size; + __u32 queue_base; + + /* Lock to queue access */ + struct mutex queue; + struct rm_queue sq; + struct rm_queue cq; + __u32 queue_size; + + struct timer_list msg_timer; + struct work_struct msg_monitor; + struct timer_list health_timer; + struct work_struct health_monitor; + struct list_head submitted_cmds; + + __u32 firewall_tripped; +}; + +#endif /* __RM_SERVICE_H */ From patchwork Tue Dec 10 18:37:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yidong Zhang X-Patchwork-Id: 13901917 Received: from NAM10-BN7-obe.outbound.protection.outlook.com (mail-bn7nam10on2052.outbound.protection.outlook.com [40.107.92.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8102F214214; Tue, 10 Dec 2024 18:38:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.92.52 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733855887; cv=fail; b=t93RIeURBapBeDvmDqSGflsUjVghAki6yhVvm4SGyhiFKQCPmk+lzsEdAkzQE1qcYGRbbSfwFetUXpGEuYbpa3ZBPmzgMfKzGZFi07ylD97cC2BRwIURpsFuEW1E3UPPE42TJF3W3StpK0iCRpMSVTpw9EgDxD1dD7xqPCyMoFA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733855887; c=relaxed/simple; bh=GpQDLaKH50MB2GBB3cqdgGDlaFb3zQl2c+JiALyAiMk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=KCEvrXFS1A/yRe8W1xuJjHh5OopApKk9yIYHDpopvCLIPZJwNqfmnMrVYrkXH7nzMPkPupMd9iSe9PXQKEbne+p6w+Htg+zc17NxjlTElu4yHNWeqMWM6oMwrvqYvE0oz1tMpvRtgfljlJ4Qs0TT2muEmBTazOUfhl0JzHAi1eU= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=a5Gd/XZT; arc=fail smtp.client-ip=40.107.92.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="a5Gd/XZT" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=FXtETrF8USuL5eNk/+J8JIkMouoTlSTaek7buB24tHo7l3J6GFiZRe1wHe/9S5nA5zZ9BfLL7CzsMemaiZlnm7Gk7x6AJEG4gydmQDSAz+vETPrXKRJHJSSuvLRoJdMUS2KXUn8NS6YmDSbSmYTtWI6rLIKmHA4sympSZLe2jKSVOk8YxocE37yXrsVR7yTA81gKNLVbjV0kpcOwZJscbhlP8sMyNt96Ul2TRU25CJ8liNoYcXBkACwumIwlu5EeuLdTCooT9cOhN3xCnD0TlPNIE4C6oRroZ7PPT4Wi80VeCi/ABwqNalEWNSISJdeEbevRXD0YRiZdCvVX8HTN5g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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; bh=8qYHfyBW3ia1q5G4plYvmmIk4ry4jwrUFeKOExRWp7Q=; b=PeRBOXSpy71nedndjiewuY69ahiAOGruZUPhF42IuZ7Lv2K68e/T3tQ0ZA96HOGgZ8M+wh4Xjswzb7lmV/lKDViLai3Mc2bE2nGS49hjx8BeuSV6eeyW5E6/cwHGGUWsKmEadrw/QRqXwySwqcWxM9ZwmEP7xEZEslS78Na0Udrc8gIvdnnw5ZFeJTQCjO/8wQtsjy6bZkI8QOiYC2PnUXaR9r07Mq1TSTGwSiVW3UxSz0P1D+mvKPlAtmDiNYcegOA5g7NQJUc9P1fFItrg3i3HV311uoOiWURg6Wazom6J+rm1JDkqdb3Ell5+E5/ytuZe92LRxHDXHkctuvbp1w== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=8qYHfyBW3ia1q5G4plYvmmIk4ry4jwrUFeKOExRWp7Q=; b=a5Gd/XZTiq8vnZyvEqa/+5Adgi0ZQ+Fo3qNsBtNG/kscHT2kA9SJMRGQyjqP3M+ulkkvaTON3jdYHaciV5H2H61CTZ782Sqx8onKaGfzqFQaXabKWwe/p/xwpR8a+kbOa1a3IMPINbMmsjtD2o7ZIGlRGnYqawj3wbqQFvJxk4U= Received: from PH7P221CA0020.NAMP221.PROD.OUTLOOK.COM (2603:10b6:510:32a::6) by CH3PR12MB8306.namprd12.prod.outlook.com (2603:10b6:610:12c::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8251.14; Tue, 10 Dec 2024 18:37:58 +0000 Received: from SN1PEPF000252A2.namprd05.prod.outlook.com (2603:10b6:510:32a:cafe::4f) by PH7P221CA0020.outlook.office365.com (2603:10b6:510:32a::6) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.8251.14 via Frontend Transport; Tue, 10 Dec 2024 18:37:57 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C Received: from SATLEXMB04.amd.com (165.204.84.17) by SN1PEPF000252A2.mail.protection.outlook.com (10.167.242.9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.8230.7 via Frontend Transport; Tue, 10 Dec 2024 18:37:57 +0000 Received: from SATLEXMB06.amd.com (10.181.40.147) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Tue, 10 Dec 2024 12:37:55 -0600 Received: from SATLEXMB03.amd.com (10.181.40.144) by SATLEXMB06.amd.com (10.181.40.147) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Tue, 10 Dec 2024 12:37:55 -0600 Received: from xsjyliu51.xilinx.com (10.180.168.240) by SATLEXMB03.amd.com (10.181.40.144) with Microsoft SMTP Server id 15.1.2507.39 via Frontend Transport; Tue, 10 Dec 2024 12:37:54 -0600 From: Yidong Zhang To: , , , , CC: Yidong Zhang , , Nishad Saraf , Prapul Krishnamurthy Subject: [PATCH V2 4/4] drivers/fpga/amd: Add load xclbin and load firmware Date: Tue, 10 Dec 2024 10:37:33 -0800 Message-ID: <20241210183734.30803-5-yidong.zhang@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241210183734.30803-1-yidong.zhang@amd.com> References: <20241210183734.30803-1-yidong.zhang@amd.com> Precedence: bulk X-Mailing-List: linux-fpga@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SN1PEPF000252A2:EE_|CH3PR12MB8306:EE_ X-MS-Office365-Filtering-Correlation-Id: c14ca5e7-707b-4339-c743-08dd1949c48c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|1800799024|82310400026|36860700013; X-Microsoft-Antispam-Message-Info: HxwKpdRrumlDz45/vWQRUuXHK5Ujacd3hcluhN4HrT8qtriubjyqefiHOP0aGvf0nb7cKEv8yWBqQ9hm9kzROqJBAwKb+yUruLY9eYUP8kToWsZpicSiGBUuiSkR8r2bkMsYoYsQCxI9kN8NvFcd1xS+5Kau2/8ZsuC4WuvBh15RTgBBjgg5Jlx4uki5ONYHqoTw6DNrCCSe6+V49l+LZ2PEDdZUwL5i+K7FQJX3muKzLQL/rOP0F8RBbWii+geqCQnwlsbL7xjIKv5PkMH8JOt47+/6iAM6GAeKXXQnLIBXlPGhuqqLWMwOAnTH3lzH8DePEsyxaxXBaSGDLnAr/SGQQaYhcysmuCNIjJczO+ljq605W7Eny8SGnXsHNmRiXs1MQHSjU8sjpAlNBFHsK9a5hp6TS0Gd11JALF8Ix2/zSXlUnGRkDeQ33Y5P8F3wbhDl6ExwhzwAfZJXeMkjHhBeRiMEXZFIF6raDZMI0HmTIeG/LccZeGzze5WkoSEyl6H3LBIvC1ntsf4ljVTG90grcO8oi44U2VerdxRHBeZyrLkE1S8qI4W2OHlkr6Q7axNXTZHGL5CaXtvE/mCrxNNoFHO1SUXPyThcQprRfJXwpL4tJj4mhD55X2pAN+Kn2fHaQxdXMT1txQrUJoyvYtaNhJmx/HEmq7p+IZ4tF+Q0DSCfT91pgT8vKslZ9P6Sojnj0hSn5v63OMDISNY7WM4mvcCEnu9C5R4orkY10JPZfyOm1sxLMbvWi9pWbSALmXTbmAhaZMZ66OTlgjqMFWOzGgZ4qc5ERPNaxKjkKMPNvUn7KGvdna4Y/lkcBhDjbLhtDLIW3HWjVjqoLtqOvx23Wzte1S8jxnV3GApGVo0U9+M5hOQsE1QMNiOxbJq8m5sp6Zazu167vwZokkRjnFNyCv5a8O3AFf+oqkrCByxSqD+BVL1Nu0SHaHb7+vK6acKIhFw/Mq5hBK1jjTiojIYF9S9fRYB3XcvG4cTtmyvO8dGl4O5AhbO3vmbIpXroIUcWFtdOWkBC0R7p0L+bQn+QKkiqhpR1W2hhikGDuNHmTSXa/AS4KaJ0d88pIwn0y4yVYwsr4oMNkQrixUivUeKWFmele31WQGHHx6h0zpzFWtmrnrsG3FMrUvHnql9y/qZMlRNqY0wnapoRsx7//SzLv+v49Ip0gGnOo1CAo6KLQ77rBDzJ8Qs/eickFL/dAToyC7kj5VaNhMpS0p+cmElDaarL81XZL9KPS2isCaQHHuYGqDum66D9s7+9rqj+xRVTMHw0CJMkjvfAv5HHx2Oq9fyG1jEx00LS4tlNCZdWztU27zF7qjE0Txx5yq9kbyHlk4klGXDvTryZhSEH1FIw2AzoGG0SlEC8s9DvWajBUv2Gya1pla17UNl6/ZmYsTrW/M7gmvdo8x8CsWLHO3Ge+BGXuEwBY2EFGlPO8vZYfFQgULBfy7ZZJeh+YA9J X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:SATLEXMB04.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(376014)(1800799024)(82310400026)(36860700013);DIR:OUT;SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Dec 2024 18:37:57.6408 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: c14ca5e7-707b-4339-c743-08dd1949c48c X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: SN1PEPF000252A2.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH3PR12MB8306 - programming FW - The base FW is downloaded onto the flash of the card. - The APU FW is downloaded once after a POR (power on reset). - Reloading the MgmtPF driver will not change any existing hardware. - programming FPGA hardware binaries - PL Data - using fpga framework ops to support re-programing FPGA - the re-programming request will be initiated from the existing UserPF driver only, and the MgmtPF driver load the matched PL Data after receiving request from the communication channel. The matching PL Data is indexed by the PL Data UUID and Base FW UUID. - The Base FW UUID identifies unique based hardware. Often called the interface UUID. - The PL Data UUID identifies unique PL design that is generated based on the base hardware. Often called xclbin UUID. - Example: 4fdebe35[...trimmed...]_96df7d[...trimmed...].xclbin | | | | +-- xclbin UUID --+ +--interface UUID --+ Co-developed-by: Nishad Saraf Signed-off-by: Nishad Saraf Co-developed-by: Prapul Krishnamurthy Signed-off-by: Prapul Krishnamurthy Signed-off-by: Yidong Zhang --- drivers/fpga/amd/Makefile | 3 +- drivers/fpga/amd/versal-pci-main.c | 137 ++++++- drivers/fpga/amd/versal-pci-rm-queue.c | 14 +- drivers/fpga/amd/versal-pci-rm-service.c | 497 +++++++++++++++++++++++ drivers/fpga/amd/versal-pci-rm-service.h | 20 + drivers/fpga/amd/versal-pci.h | 2 + 6 files changed, 649 insertions(+), 24 deletions(-) create mode 100644 drivers/fpga/amd/versal-pci-rm-service.c diff --git a/drivers/fpga/amd/Makefile b/drivers/fpga/amd/Makefile index b2ffdbf23400..ffe4ead0d55e 100644 --- a/drivers/fpga/amd/Makefile +++ b/drivers/fpga/amd/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_AMD_VERSAL_PCI) += versal-pci.o versal-pci-$(CONFIG_AMD_VERSAL_PCI) := versal-pci-main.o \ versal-pci-comm-chan.o \ - versal-pci-rm-queue.o + versal-pci-rm-queue.o \ + versal-pci-rm-service.o diff --git a/drivers/fpga/amd/versal-pci-main.c b/drivers/fpga/amd/versal-pci-main.c index a3b83197c6d5..b56449932c05 100644 --- a/drivers/fpga/amd/versal-pci-main.c +++ b/drivers/fpga/amd/versal-pci-main.c @@ -9,6 +9,8 @@ #include "versal-pci.h" #include "versal-pci-comm-chan.h" +#include "versal-pci-rm-service.h" +#include "versal-pci-rm-queue.h" #define DRV_NAME "amd-versal-pci" @@ -18,22 +20,55 @@ static int versal_pci_fpga_write_init(struct fpga_manager *mgr, struct fpga_image_info *info, const char *buf, size_t count) { - /* TODO */ - return 0; + struct fpga_device *fdev = mgr->priv; + struct fw_tnx *tnx = &fdev->fw; + int ret; + + ret = rm_queue_create_cmd(fdev->vdev->rdev, tnx->opcode, &tnx->cmd); + if (ret) { + fdev->state = FPGA_MGR_STATE_WRITE_INIT_ERR; + return ret; + } + + fdev->state = FPGA_MGR_STATE_WRITE_INIT; + return ret; } static int versal_pci_fpga_write(struct fpga_manager *mgr, const char *buf, size_t count) { - /* TODO */ - return 0; + struct fpga_device *fdev = mgr->priv; + int ret; + + ret = rm_queue_data_init(fdev->fw.cmd, buf, count); + if (ret) { + fdev->state = FPGA_MGR_STATE_WRITE_ERR; + rm_queue_destory_cmd(fdev->fw.cmd); + return ret; + } + + fdev->state = FPGA_MGR_STATE_WRITE; + return ret; } static int versal_pci_fpga_write_complete(struct fpga_manager *mgr, struct fpga_image_info *info) { - /* TODO */ - return 0; + struct fpga_device *fdev = mgr->priv; + int ret; + + ret = rm_queue_send_cmd(fdev->fw.cmd, RM_CMD_WAIT_DOWNLOAD_TIMEOUT); + if (ret) { + fdev->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR; + vdev_err(fdev->vdev, "Send cmd failed:%d, cid:%d", ret, fdev->fw.id); + } else { + fdev->state = FPGA_MGR_STATE_WRITE_COMPLETE; + } + + rm_queue_data_fini(fdev->fw.cmd); + rm_queue_destory_cmd(fdev->fw.cmd); + memset(&fdev->fw, 0, sizeof(fdev->fw)); + return ret; } static enum fpga_mgr_states versal_pci_fpga_state(struct fpga_manager *mgr) @@ -97,10 +132,20 @@ static struct fpga_device *versal_pci_fpga_init(struct versal_pci_device *vdev) return ERR_PTR(ret); } - /* Place holder for rm_queue_get_fw_id(vdev->rdev) */ + ret = rm_queue_get_fw_id(vdev->rdev); + if (ret) { + vdev_warn(vdev, "Failed to get fw_id"); + ret = -EINVAL; + goto unregister_fpga_mgr; + } versal_pci_uuid_parse(vdev, &vdev->intf_uuid); return fdev; + +unregister_fpga_mgr: + fpga_mgr_unregister(fdev->mgr); + + return ERR_PTR(ret); } static int versal_pci_program_axlf(struct versal_pci_device *vdev, char *data, size_t size) @@ -161,31 +206,84 @@ int versal_pci_load_xclbin(struct versal_pci_device *vdev, uuid_t *xuuid) static enum fw_upload_err versal_pci_fw_prepare(struct fw_upload *fw_upload, const u8 *data, u32 size) { - /* TODO */ + struct firmware_device *fwdev = fw_upload->dd_handle; + struct axlf *xsabin = (struct axlf *)data; + int ret; + + ret = memcmp(xsabin->magic, VERSAL_XCLBIN_MAGIC_ID, sizeof(VERSAL_XCLBIN_MAGIC_ID)); + if (ret) { + vdev_err(fwdev->vdev, "Invalid device firmware"); + return FW_UPLOAD_ERR_INVALID_SIZE; + } + + /* Firmware size should never be over 1G and less than size of struct axlf */ + if (!size || size != xsabin->header.length || size < sizeof(*xsabin) || + size > 1024 * 1024 * 1024) { + vdev_err(fwdev->vdev, "Invalid device firmware size"); + return FW_UPLOAD_ERR_INVALID_SIZE; + } + + ret = rm_queue_create_cmd(fwdev->vdev->rdev, RM_QUEUE_OP_LOAD_FW, + &fwdev->cmd); + if (ret) + return FW_UPLOAD_ERR_RW_ERROR; + + uuid_copy(&fwdev->uuid, &xsabin->header.uuid); return FW_UPLOAD_ERR_NONE; } static enum fw_upload_err versal_pci_fw_write(struct fw_upload *fw_upload, const u8 *data, u32 offset, u32 size, u32 *written) { - /* TODO */ + struct firmware_device *fwdev = fw_upload->dd_handle; + int ret; + + ret = rm_queue_data_init(fwdev->cmd, data, size); + if (ret) + return FW_UPLOAD_ERR_RW_ERROR; + + *written = size; return FW_UPLOAD_ERR_NONE; } static enum fw_upload_err versal_pci_fw_poll_complete(struct fw_upload *fw_upload) { - /* TODO */ + struct firmware_device *fwdev = fw_upload->dd_handle; + int ret; + + vdev_info(fwdev->vdev, "Programming device firmware: %pUb", &fwdev->uuid); + + ret = rm_queue_send_cmd(fwdev->cmd, RM_CMD_WAIT_DOWNLOAD_TIMEOUT); + if (ret) { + vdev_err(fwdev->vdev, "Send cmd failedi:%d, cid %d", ret, fwdev->id); + return FW_UPLOAD_ERR_HW_ERROR; + } + + vdev_info(fwdev->vdev, "Successfully programmed device firmware: %pUb", + &fwdev->uuid); return FW_UPLOAD_ERR_NONE; } static void versal_pci_fw_cancel(struct fw_upload *fw_upload) { - /* TODO */ + struct firmware_device *fwdev = fw_upload->dd_handle; + + vdev_warn(fwdev->vdev, "canceled"); + rm_queue_withdraw_cmd(fwdev->cmd); } static void versal_pci_fw_cleanup(struct fw_upload *fw_upload) { - /* TODO */ + struct firmware_device *fwdev = fw_upload->dd_handle; + + if (!fwdev->cmd) + return; + + rm_queue_data_fini(fwdev->cmd); + rm_queue_destory_cmd(fwdev->cmd); + + fwdev->cmd = NULL; + fwdev->id = 0; } static const struct fw_upload_ops versal_pci_fw_ops = { @@ -240,23 +338,31 @@ static void versal_pci_device_teardown(struct versal_pci_device *vdev) versal_pci_fpga_fini(vdev->fdev); versal_pci_fw_upload_fini(vdev->fwdev); versal_pci_comm_chan_fini(vdev->ccdev); + versal_pci_rm_fini(vdev->rdev); } static int versal_pci_device_setup(struct versal_pci_device *vdev) { int ret; + vdev->rdev = versal_pci_rm_init(vdev); + if (IS_ERR(vdev->rdev)) { + ret = PTR_ERR(vdev->rdev); + vdev_err(vdev, "Failed to init remote queue, err %d", ret); + return ret; + } + vdev->fwdev = versal_pci_fw_upload_init(vdev); if (IS_ERR(vdev->fwdev)) { ret = PTR_ERR(vdev->fwdev); vdev_err(vdev, "Failed to init FW uploader, err %d", ret); - return ret; + goto rm_fini; } vdev->ccdev = versal_pci_comm_chan_init(vdev); if (IS_ERR(vdev->ccdev)) { ret = PTR_ERR(vdev->ccdev); - vdev_err(vdev, "Failed to init comms channel, err %d", ret); + vdev_err(vdev, "Failed to init comm channel, err %d", ret); goto upload_fini; } @@ -272,7 +378,8 @@ static int versal_pci_device_setup(struct versal_pci_device *vdev) versal_pci_comm_chan_fini(vdev->ccdev); upload_fini: versal_pci_fw_upload_fini(vdev->fwdev); - +rm_fini: + versal_pci_rm_fini(vdev->rdev); return ret; } diff --git a/drivers/fpga/amd/versal-pci-rm-queue.c b/drivers/fpga/amd/versal-pci-rm-queue.c index 92f2e1165052..e62aa6791a95 100644 --- a/drivers/fpga/amd/versal-pci-rm-queue.c +++ b/drivers/fpga/amd/versal-pci-rm-queue.c @@ -23,37 +23,35 @@ static inline struct rm_device *to_rdev_msg_timer(struct timer_list *t) static inline u32 rm_io_read(struct rm_device *rdev, u32 offset) { - /* TODO */ - return 0; + return rm_reg_read(rdev, RM_PCI_IO_BAR_OFF + offset); } static inline int rm_io_write(struct rm_device *rdev, u32 offset, u32 value) { - /* TODO */ + rm_reg_write(rdev, RM_PCI_IO_BAR_OFF + offset, value); return 0; } static inline u32 rm_queue_read(struct rm_device *rdev, u32 offset) { - /* TODO */ - return 0; + return rm_reg_read(rdev, RM_PCI_SHMEM_BAR_OFF + rdev->queue_base + offset); } static inline void rm_queue_write(struct rm_device *rdev, u32 offset, u32 value) { - /* TODO */ + rm_reg_write(rdev, RM_PCI_SHMEM_BAR_OFF + rdev->queue_base + offset, value); } static inline void rm_queue_bulk_read(struct rm_device *rdev, u32 offset, u32 *value, u32 size) { - /* TODO */ + rm_bulk_reg_read(rdev, RM_PCI_SHMEM_BAR_OFF + rdev->queue_base + offset, value, size); } static inline void rm_queue_bulk_write(struct rm_device *rdev, u32 offset, u32 *value, u32 size) { - /* TODO */ + rm_bulk_reg_write(rdev, RM_PCI_SHMEM_BAR_OFF + rdev->queue_base + offset, value, size); } static inline u32 rm_queue_get_cidx(struct rm_device *rdev, enum rm_queue_type type) diff --git a/drivers/fpga/amd/versal-pci-rm-service.c b/drivers/fpga/amd/versal-pci-rm-service.c new file mode 100644 index 000000000000..0a1d96a432b2 --- /dev/null +++ b/drivers/fpga/amd/versal-pci-rm-service.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Versal PCIe device + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + */ + +#include +#include +#include + +#include "versal-pci.h" +#include "versal-pci-rm-service.h" +#include "versal-pci-rm-queue.h" + +static DEFINE_IDA(rm_cmd_ids); + +static void rm_uninstall_health_monitor(struct rm_device *rdev); + +static inline struct rm_device *to_rdev_health_monitor(struct work_struct *w) +{ + return container_of(w, struct rm_device, health_monitor); +} + +static inline struct rm_device *to_rdev_health_timer(struct timer_list *t) +{ + return container_of(t, struct rm_device, health_timer); +} + +u32 rm_reg_read(struct rm_device *rdev, u32 offset) +{ + return readl(rdev->vdev->io_regs + offset); +} + +void rm_reg_write(struct rm_device *rdev, u32 offset, const u32 value) +{ + writel(value, rdev->vdev->io_regs + offset); +} + +void rm_bulk_reg_read(struct rm_device *rdev, u32 offset, u32 *value, size_t size) +{ + void __iomem *src = rdev->vdev->io_regs + offset; + void *dst = (void *)value; + + memcpy_fromio(dst, src, size); + /* Barrier of reading data from device */ + rmb(); +} + +void rm_bulk_reg_write(struct rm_device *rdev, u32 offset, const void *value, size_t size) +{ + void __iomem *dst = rdev->vdev->io_regs + offset; + + memcpy_toio(dst, value, size); + /* Barrier of writing data to device */ + wmb(); +} + +static inline u32 rm_shmem_read(struct rm_device *rdev, u32 offset) +{ + return rm_reg_read(rdev, RM_PCI_SHMEM_BAR_OFF + offset); +} + +static inline void rm_shmem_bulk_read(struct rm_device *rdev, u32 offset, + u32 *value, u32 size) +{ + rm_bulk_reg_read(rdev, RM_PCI_SHMEM_BAR_OFF + offset, value, size); +} + +static inline void rm_shmem_bulk_write(struct rm_device *rdev, u32 offset, + const void *value, u32 size) +{ + rm_bulk_reg_write(rdev, RM_PCI_SHMEM_BAR_OFF + offset, value, size); +} + +void rm_queue_destory_cmd(struct rm_cmd *cmd) +{ + ida_free(&rm_cmd_ids, cmd->sq_msg.hdr.id); + kfree(cmd); +} + +static int rm_queue_copy_response(struct rm_cmd *cmd, void *buffer, ssize_t len) +{ + struct rm_cmd_cq_log_page *result = &cmd->cq_msg.data.page; + u64 off = cmd->sq_msg.data.page.address; + + if (!result->len || len < result->len) { + vdev_err(cmd->rdev->vdev, "Invalid response or buffer size"); + return -EINVAL; + } + + rm_shmem_bulk_read(cmd->rdev, off, (u32 *)buffer, result->len); + return 0; +} + +static void rm_queue_payload_fini(struct rm_cmd *cmd) +{ + up(&cmd->rdev->cq.data_lock); +} + +static int rm_queue_payload_init(struct rm_cmd *cmd, + enum rm_cmd_log_page_type type) +{ + struct rm_device *rdev = cmd->rdev; + int ret; + + ret = down_interruptible(&rdev->cq.data_lock); + if (ret) + return ret; + + cmd->sq_msg.data.page.address = rdev->cq.data_offset; + cmd->sq_msg.data.page.size = rdev->cq.data_size; + cmd->sq_msg.data.page.reserved1 = 0; + cmd->sq_msg.data.page.type = FIELD_PREP(RM_CMD_LOG_PAGE_TYPE_MASK, + type); + return 0; +} + +void rm_queue_data_fini(struct rm_cmd *cmd) +{ + up(&cmd->rdev->sq.data_lock); +} + +int rm_queue_data_init(struct rm_cmd *cmd, const char *buffer, ssize_t size) +{ + struct rm_device *rdev = cmd->rdev; + int ret; + + if (!size || size > rdev->sq.data_size) { + vdev_err(rdev->vdev, "Unsupported file size"); + return -ENOMEM; + } + + ret = down_interruptible(&rdev->sq.data_lock); + if (ret) + return ret; + + rm_shmem_bulk_write(cmd->rdev, rdev->sq.data_offset, buffer, size); + + cmd->sq_msg.data.bin.address = rdev->sq.data_offset; + cmd->sq_msg.data.bin.size = size; + return 0; +} + +int rm_queue_create_cmd(struct rm_device *rdev, enum rm_queue_opcode opcode, + struct rm_cmd **cmd_ptr) +{ + struct rm_cmd *cmd = NULL; + int ret, id; + u16 size; + + if (rdev->firewall_tripped) + return -ENODEV; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + cmd->rdev = rdev; + + switch (opcode) { + case RM_QUEUE_OP_LOAD_XCLBIN: + fallthrough; + case RM_QUEUE_OP_LOAD_FW: + fallthrough; + case RM_QUEUE_OP_LOAD_APU_FW: + size = sizeof(struct rm_cmd_sq_bin); + break; + case RM_QUEUE_OP_GET_LOG_PAGE: + size = sizeof(struct rm_cmd_sq_log_page); + break; + case RM_QUEUE_OP_IDENTIFY: + size = 0; + break; + case RM_QUEUE_OP_VMR_CONTROL: + size = sizeof(struct rm_cmd_sq_ctrl); + break; + default: + vdev_err(rdev->vdev, "Invalid cmd opcode %d", opcode); + ret = -EINVAL; + goto error; + } + + cmd->opcode = opcode; + cmd->sq_msg.hdr.opcode = FIELD_PREP(RM_CMD_SQ_HDR_OPS_MSK, opcode); + cmd->sq_msg.hdr.msg_size = FIELD_PREP(RM_CMD_SQ_HDR_SIZE_MSK, size); + + id = ida_alloc_range(&rm_cmd_ids, RM_CMD_ID_MIN, RM_CMD_ID_MAX, GFP_KERNEL); + if (id < 0) { + vdev_err(rdev->vdev, "Failed to alloc cmd ID: %d", id); + ret = id; + goto error; + } + cmd->sq_msg.hdr.id = id; + + init_completion(&cmd->executed); + + *cmd_ptr = cmd; + return 0; +error: + kfree(cmd); + return ret; +} + +static int rm_queue_verify(struct rm_device *rdev) +{ + struct versal_pci_device *vdev = rdev->vdev; + struct rm_cmd_cq_identify *result; + struct rm_cmd *cmd; + u32 major, minor; + int ret; + + ret = rm_queue_create_cmd(rdev, RM_QUEUE_OP_IDENTIFY, &cmd); + if (ret) + return ret; + + ret = rm_queue_send_cmd(cmd, RM_CMD_WAIT_CONFIG_TIMEOUT); + if (ret) + goto error; + + result = &cmd->cq_msg.data.identify; + major = result->major; + minor = result->minor; + vdev_dbg(vdev, "VMR version %d.%d", major, minor); + if (!major) { + vdev_err(vdev, "VMR version is unsupported"); + ret = -EOPNOTSUPP; + } + +error: + rm_queue_destory_cmd(cmd); + return ret; +} + +static int rm_check_apu_status(struct rm_device *rdev, bool *status) +{ + struct rm_cmd_cq_control *result; + struct rm_cmd *cmd; + int ret; + + ret = rm_queue_create_cmd(rdev, RM_QUEUE_OP_VMR_CONTROL, &cmd); + if (ret) + return ret; + + ret = rm_queue_send_cmd(cmd, RM_CMD_WAIT_CONFIG_TIMEOUT); + if (ret) + goto error; + + result = &cmd->cq_msg.data.ctrl; + *status = FIELD_GET(RM_CMD_VMR_CONTROL_PS_MASK, result->status); + + rm_queue_destory_cmd(cmd); + return 0; + +error: + rm_queue_destory_cmd(cmd); + return ret; +} + +static int rm_download_apu_fw(struct rm_device *rdev, char *data, ssize_t size) +{ + struct rm_cmd *cmd; + int ret; + + ret = rm_queue_create_cmd(rdev, RM_QUEUE_OP_LOAD_APU_FW, &cmd); + if (ret) + return ret; + + ret = rm_queue_data_init(cmd, data, size); + if (ret) + goto done; + + ret = rm_queue_send_cmd(cmd, RM_CMD_WAIT_DOWNLOAD_TIMEOUT); + +done: + rm_queue_destory_cmd(cmd); + return ret; +} + +int rm_queue_boot_apu(struct rm_device *rdev) +{ + char *bin = "xilinx/xrt-versal-apu.xsabin"; + const struct firmware *fw = NULL; + bool status; + int ret; + + ret = rm_check_apu_status(rdev, &status); + if (ret) { + vdev_err(rdev->vdev, "Failed to get APU status"); + return ret; + } + + if (status) { + vdev_dbg(rdev->vdev, "APU online. Skipping APU FW download"); + return 0; + } + + ret = request_firmware(&fw, bin, &rdev->vdev->pdev->dev); + if (ret) { + vdev_warn(rdev->vdev, "Request APU FW %s failed %d", bin, ret); + return ret; + } + + vdev_dbg(rdev->vdev, "Starting... APU FW download"); + ret = rm_download_apu_fw(rdev, (char *)fw->data, fw->size); + vdev_dbg(rdev->vdev, "Finished... APU FW download %d", ret); + + if (ret) + vdev_err(rdev->vdev, "Failed to download APU FW, ret:%d", ret); + + release_firmware(fw); + + return ret; +} + +static void rm_check_health(struct work_struct *w) +{ + struct rm_device *rdev = to_rdev_health_monitor(w); + u32 max_len = PAGE_SIZE; + struct rm_cmd *cmd; + int ret; + + ret = rm_queue_create_cmd(rdev, RM_QUEUE_OP_GET_LOG_PAGE, &cmd); + if (ret) + return; + + ret = rm_queue_payload_init(cmd, RM_CMD_LOG_PAGE_AXI_TRIP_STATUS); + if (ret) + goto destroy_cmd; + + ret = rm_queue_send_cmd(cmd, RM_CMD_WAIT_CONFIG_TIMEOUT); + if (ret == -ETIME || ret == -EINVAL) + goto payload_fini; + + if (ret) { + u32 log_len = cmd->cq_msg.data.page.len; + + if (log_len > max_len) { + vdev_warn(rdev->vdev, "msg size %d is greater than requested %d", + log_len, max_len); + log_len = max_len; + } + + if (log_len) { + char *buffer = vzalloc(log_len); + + if (!buffer) + goto payload_fini; + + ret = rm_queue_copy_response(cmd, buffer, log_len); + if (ret) { + vfree(buffer); + goto payload_fini; + } + + vdev_err(rdev->vdev, "%s", buffer); + vfree(buffer); + + } else { + vdev_err(rdev->vdev, "firewall check ret%d", ret); + } + + rdev->firewall_tripped = 1; + } + +payload_fini: + rm_queue_payload_fini(cmd); +destroy_cmd: + rm_queue_destory_cmd(cmd); + + vdev_dbg(rdev->vdev, "check result: %d", ret); +} + +static void rm_sched_health_check(struct timer_list *t) +{ + struct rm_device *rdev = to_rdev_health_timer(t); + + if (rdev->firewall_tripped) { + vdev_err(rdev->vdev, "Firewall tripped, health check paused. Please reset card"); + return; + } + /* Schedule a work in the general workqueue */ + schedule_work(&rdev->health_monitor); + /* Periodic timer */ + mod_timer(&rdev->health_timer, jiffies + RM_HEALTH_CHECK_TIMER); +} + +static void rm_uninstall_health_monitor(struct rm_device *rdev) +{ + del_timer_sync(&rdev->health_timer); + cancel_work_sync(&rdev->health_monitor); +} + +static void rm_install_health_monitor(struct rm_device *rdev) +{ + INIT_WORK(&rdev->health_monitor, &rm_check_health); + timer_setup(&rdev->health_timer, &rm_sched_health_check, 0); + mod_timer(&rdev->health_timer, jiffies + RM_HEALTH_CHECK_TIMER); +} + +void versal_pci_rm_fini(struct rm_device *rdev) +{ + rm_uninstall_health_monitor(rdev); + rm_queue_fini(rdev); +} + +struct rm_device *versal_pci_rm_init(struct versal_pci_device *vdev) +{ + struct rm_header *header; + struct rm_device *rdev; + u32 status; + int ret; + + rdev = devm_kzalloc(&vdev->pdev->dev, sizeof(*rdev), GFP_KERNEL); + if (!rdev) + return ERR_PTR(-ENOMEM); + + rdev->vdev = vdev; + header = &rdev->rm_metadata; + + rm_shmem_bulk_read(rdev, RM_HDR_OFF, (u32 *)header, sizeof(*header)); + if (header->magic != RM_HDR_MAGIC_NUM) { + vdev_err(vdev, "Invalid RM header 0x%x", header->magic); + ret = -ENODEV; + goto err; + } + + status = rm_shmem_read(rdev, header->status_off); + if (!status) { + vdev_err(vdev, "RM status %d is not ready", status); + ret = -ENODEV; + goto err; + } + + rdev->queue_buffer_size = header->data_end - header->data_start + 1; + rdev->queue_buffer_start = header->data_start; + rdev->queue_base = header->queue_base; + + ret = rm_queue_init(rdev); + if (ret) { + vdev_err(vdev, "Failed to init cmd queue, ret %d", ret); + ret = -ENODEV; + goto err; + } + + ret = rm_queue_verify(rdev); + if (ret) { + vdev_err(vdev, "Failed to verify cmd queue, ret %d", ret); + ret = -ENODEV; + goto queue_fini; + } + + ret = rm_queue_boot_apu(rdev); + if (ret) { + vdev_err(vdev, "Failed to bringup APU, ret %d", ret); + ret = -ENODEV; + goto queue_fini; + } + + rm_install_health_monitor(rdev); + + return rdev; +queue_fini: + rm_queue_fini(rdev); +err: + return ERR_PTR(ret); +} + +int rm_queue_get_fw_id(struct rm_device *rdev) +{ + struct rm_cmd *cmd; + int ret; + + ret = rm_queue_create_cmd(rdev, RM_QUEUE_OP_GET_LOG_PAGE, &cmd); + if (ret) + return ret; + + ret = rm_queue_payload_init(cmd, RM_CMD_LOG_PAGE_FW_ID); + if (ret) + goto destroy_cmd; + + ret = rm_queue_send_cmd(cmd, RM_CMD_WAIT_CONFIG_TIMEOUT); + if (ret) + goto payload_fini; + + ret = rm_queue_copy_response(cmd, rdev->vdev->fw_id, sizeof(rdev->vdev->fw_id)); + if (ret) + goto payload_fini; + + vdev_info(rdev->vdev, "fw_id %s", rdev->vdev->fw_id); + +payload_fini: + rm_queue_payload_fini(cmd); +destroy_cmd: + rm_queue_destory_cmd(cmd); + + return ret; +} diff --git a/drivers/fpga/amd/versal-pci-rm-service.h b/drivers/fpga/amd/versal-pci-rm-service.h index 85a78257770a..90796567f0d3 100644 --- a/drivers/fpga/amd/versal-pci-rm-service.h +++ b/drivers/fpga/amd/versal-pci-rm-service.h @@ -206,4 +206,24 @@ struct rm_device { __u32 firewall_tripped; }; +/* rm service init api */ +struct rm_device *versal_pci_rm_init(struct versal_pci_device *vdev); +void versal_pci_rm_fini(struct rm_device *rdev); + +/* rm services APIs */ +int rm_queue_create_cmd(struct rm_device *rdev, enum rm_queue_opcode opcode, + struct rm_cmd **cmd_ptr); +void rm_queue_destory_cmd(struct rm_cmd *cmd); + +int rm_queue_data_init(struct rm_cmd *cmd, const char *buffer, ssize_t size); +void rm_queue_data_fini(struct rm_cmd *cmd); +int rm_queue_get_fw_id(struct rm_device *rdev); +int rm_queue_boot_apu(struct rm_device *rdev); + +/* rm bar register operation APIs */ +u32 rm_reg_read(struct rm_device *rdev, u32 offset); +void rm_reg_write(struct rm_device *rdev, u32 offset, const u32 value); +void rm_bulk_reg_read(struct rm_device *rdev, u32 offset, u32 *value, size_t size); +void rm_bulk_reg_write(struct rm_device *rdev, u32 offset, const void *value, size_t size); + #endif /* __RM_SERVICE_H */ diff --git a/drivers/fpga/amd/versal-pci.h b/drivers/fpga/amd/versal-pci.h index 6c1ca3ce505d..5d3f793a5b68 100644 --- a/drivers/fpga/amd/versal-pci.h +++ b/drivers/fpga/amd/versal-pci.h @@ -27,6 +27,7 @@ struct versal_pci_device; struct comm_chan_device; +struct rm_cmd; struct axlf_header { __u64 length; @@ -69,6 +70,7 @@ struct firmware_device { struct versal_pci_device { struct pci_dev *pdev; + struct rm_device *rdev; struct fpga_device *fdev; struct comm_chan_device *ccdev; struct firmware_device *fwdev;