From patchwork Tue Jul 25 14:06:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tanmay Shah X-Patchwork-Id: 1812713 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=amd.com header.i=@amd.com header.a=rsa-sha256 header.s=selector1 header.b=LB6LMpDp; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4R9Lr15sl6z1yYc for ; Wed, 26 Jul 2023 01:42:09 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 387D98679D; Tue, 25 Jul 2023 17:40:59 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=amd.com header.i=@amd.com header.b="LB6LMpDp"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id DF86A860AC; Tue, 25 Jul 2023 16:08:16 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from NAM10-DM6-obe.outbound.protection.outlook.com (mail-dm6nam10on20624.outbound.protection.outlook.com [IPv6:2a01:111:f400:7e88::624]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 1AED5860AC for ; Tue, 25 Jul 2023 16:08:10 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: phobos.denx.de; spf=fail smtp.mailfrom=tanmay.shah@amd.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=F124XXmx9flzvzSFys4aTMubtFwX+z0Kukse/FELt3/2asVwmZpyq29DeDl+u/jDXBOugzBhigaW94sOvgHvOAkcfOuVv61bQrMBHvFymQ5ED0HrvbJPBUsoQIWTCBVb+x5l3oj2cfQ3qUvofCqCro+fprEfI1I2IXUzZi9ouQXyEJxVh2n9gMFCM2v0+6n7UGVF7mm5dl0BolN4ZY8JdrcLbX49LlEn/zxONTGqOrBSqZ5PeYTJ4O1RI00JM0LE+G2O9QnK+6M97WbqNcT+pGv27vQIGvaRz08xpr8MlILCAuhrUvfkueePW7j8vCXyurbtwAyMHEVuAs81RFuMBQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; 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=3RPcHYyAT62lv8UEOqcgPEUvwrLqKBhaQmIqyHF09pw=; b=eJ8OVDxC+OHcgwmuO7T22DEVu+63/zX97ggP3danF1DuYDmo3A557eNyvGwQVVkcPoPAuu/wgirBxsRYHB+9vbTHa+423yMUm3xPEO+SO8lUJLOFIoVMJ2V+rKos+0aAJ0gcoNgMTXL1cD9EGYhanoqvaEno0Y0oLtUlGHLG1RmEaGRJeP/4srn+A8bay08hvKnj/88RKDwSKuyhjjs4HmTtucUFumHpiq7rOn/oiqaivjLc/8K+6u4dLNKFLBSfRGBa/CUgS8Q5WIm657iLznph1Xqo1Y48ibGT1CUHGU3cm+RWVRPNgpOb9oY5qylEVXLGkLnHVTXbIphzXAFDKw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=chromium.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 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=3RPcHYyAT62lv8UEOqcgPEUvwrLqKBhaQmIqyHF09pw=; b=LB6LMpDpO3834o2WcStjlA2kFoGzy9DBpL1cV8hO1timELwBSmj7rBSM1hVHdZJOze0mHMLbHszlubTVmzS6yNceynp8CRfyQDNjSAh+5BTc734bsqa+7CVa/JOJUdRkWUKT4HeueaI3pCAJJGXQeA+WD1F+jWc3hqY6LCRM9kw= Received: from DS7PR05CA0078.namprd05.prod.outlook.com (2603:10b6:8:57::24) by SJ0PR12MB7458.namprd12.prod.outlook.com (2603:10b6:a03:48d::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6609.33; Tue, 25 Jul 2023 14:08:06 +0000 Received: from DM6NAM11FT082.eop-nam11.prod.protection.outlook.com (2603:10b6:8:57:cafe::92) by DS7PR05CA0078.outlook.office365.com (2603:10b6:8:57::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6631.25 via Frontend Transport; Tue, 25 Jul 2023 14:08:05 +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 DM6NAM11FT082.mail.protection.outlook.com (10.13.173.107) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.6631.29 via Frontend Transport; Tue, 25 Jul 2023 14:08:05 +0000 Received: from SATLEXMB04.amd.com (10.181.40.145) 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.27; Tue, 25 Jul 2023 09:08:02 -0500 Received: from xsjtanmays50.xilinx.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server id 15.1.2507.27 via Frontend Transport; Tue, 25 Jul 2023 09:08:01 -0500 From: Tanmay Shah To: Simon Glass , Tom Rini CC: , , , Michal Simek , Venkatesh Abbarapu , Mathieu Poirier , Nishanth Menon , Tanmay Shah Subject: [RFC PATCH 03/10] remoteproc: add remoteproc virtio transport driver Date: Tue, 25 Jul 2023 07:06:43 -0700 Message-ID: <20230725140650.951581-4-tanmay.shah@amd.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230725140650.951581-1-tanmay.shah@amd.com> References: <20230725140650.951581-1-tanmay.shah@amd.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT082:EE_|SJ0PR12MB7458:EE_ X-MS-Office365-Filtering-Correlation-Id: ea6b8398-66e7-49fb-ea8d-08db8d18911a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 2QyzL6GKLUldokVcZFu2/ePJ7IOnCfHw1XAU2YvNJ+R51cK4auJfw1ZFE80iZBKp2dKXVkvS7A6UkhOqGWDUGg9LC7kIQ281gexRGiYsJvz26fEOkpTpVlK/ifEO1b5Xv5ytLIpsjKZmVct0E7u5CrgCw0/k7UcDYv2uxPXblVVEhbYq3dJMxa33t560q7ab6chFNlzQR5lpp9NJDJclWs7t39+rKjl9P9fLm+wqQ7hiM/Dt6yLtpMUv+HcYeiS5Fco/QRj8rL0Z0VeqvZQm1IdTVwTvh8crojv/UsgNfr5AS0/kg1lp28kQxKi0Ks76zBhX5gOTCrQTNFBrY225Uf44BkTlxGCQzdReEOus25Fi+udQNyhJTJPgUStM9e/qDLqc4xvr98UTzRVTQTcxe4IKwvxKim1gUBtypIFviQLokC7MazdLqUizaClKftiB0Za2ft5188CVIzbcpUO2YynesSjFv4FDN2mBkBoPGnT+fahB9JX8OaMkZIirIGaBatdyqGFL9DfbIaZgOqgEYw17ghyO3FmgfixSHvwDBRYapFP7X6CzIFvS1pKFgYMiAa7sWzIQulCLu0bKKeNqFH3SsjO+G3beUj4z+ACrxdNulZEeBIN4oMu2eocudljNtGX6rR2e+l/Xl8nOWkpl4RJfVnt3D5HFDm0KHSzc4I0HYktfyscFYeKf6ceDeZfGqHa5bMXPeh0gudky1ez/LSNSG87wZNcSxi79QlxmvW3lZzNMKhaNr/CwFU69WlAA 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:(13230028)(4636009)(346002)(136003)(396003)(39860400002)(376002)(82310400008)(451199021)(40470700004)(36840700001)(46966006)(54906003)(70206006)(70586007)(426003)(2616005)(47076005)(36756003)(83380400001)(36860700001)(40480700001)(86362001)(82740400003)(81166007)(356005)(478600001)(110136005)(336012)(1076003)(6666004)(26005)(966005)(30864003)(186003)(40460700003)(41300700001)(5660300002)(316002)(2906002)(4326008)(8676002)(8936002)(44832011)(36900700001); DIR:OUT; SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 25 Jul 2023 14:08:05.5467 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ea6b8398-66e7-49fb-ea8d-08db8d18911a 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: DM6NAM11FT082.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR12MB7458 X-Mailman-Approved-At: Tue, 25 Jul 2023 17:40:30 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean Remoteproc virtio is virtio transport layer driver for remoteproc. Implement virtio config ops used by actual virtio driver using remoteproc virtio device Ported from the Linux kernel version 6.4-rc2 (d848a4819d85), Introduced in kernel version v3.10 (ac8954a41393) file: drivers/remoteproc/remoteproc_virtio.c. Signed-off-by: Tanmay Shah --- MAINTAINERS | 6 + drivers/remoteproc/Kconfig | 11 + drivers/remoteproc/Makefile | 1 + drivers/remoteproc/rproc-uclass.c | 42 ++- drivers/remoteproc/rproc_virtio.c | 422 ++++++++++++++++++++++++++++++ drivers/virtio/virtio_ring.c | 16 ++ include/remoteproc.h | 66 +++-- include/rproc_virtio.h | 29 ++ include/virtio.h | 3 + include/virtio_ring.h | 17 ++ 10 files changed, 593 insertions(+), 20 deletions(-) create mode 100644 drivers/remoteproc/rproc_virtio.c create mode 100644 include/rproc_virtio.h diff --git a/MAINTAINERS b/MAINTAINERS index 87991cccdd..c4a32a0956 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1319,6 +1319,12 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-nand-flash.git F: drivers/mtd/nand/raw/ +REMOTEPROC +M: Tanmay Shah +S: Maintained +F: drivers/remoteproc/rproc_virtio.c +F: include/rproc_virtio.h + RISC-V M: Rick Chen M: Leo diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 27e4a60ff5..b758c248e4 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -102,4 +102,15 @@ config REMOTEPROC_TI_IPU help Say 'y' here to add support for TI' K3 remoteproc driver. +config REMOTEPROC_VIRTIO + bool "Support remoteproc virtio devices" + select REMOTEPROC + select VIRTIO + depends on DM + help + Say 'y' here to add support of remoteproc virtio devices. + rproc_virtio is virtio transport layer driver. The transport + drivers provide a set of ops for the real virtio device + driver to call. + endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index fbe9c172bc..61fdb87efb 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o obj-$(CONFIG_REMOTEPROC_TI_PRU) += pru_rproc.o obj-$(CONFIG_REMOTEPROC_TI_IPU) += ipu_rproc.o +obj-$(CONFIG_REMOTEPROC_VIRTIO) += rproc_virtio.o diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index d697639cdd..3aebaf6187 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -279,6 +280,33 @@ static int rproc_config_pagetable(struct udevice *dev, unsigned int virt, return 0; } +/** + * rproc_find_res_by_name() - After parsing the resource table add the mappings + * @dev: device we finished probing + * @name: name of rproc_mem_entry resource + * + * Return: If failed NULL, else first carveout entry with matching name. + */ +struct rproc_mem_entry *rproc_find_res_by_name(struct udevice *dev, + const char *name) +{ + struct rproc *rproc = rproc_get_cfg(dev); + struct rproc_mem_entry *mapping = NULL; + int ret; + + if (!rproc) + return NULL; + + list_for_each_entry(mapping, &rproc->mappings.node, node) { + ret = strcmp(mapping->name, name); + if (!ret) + return mapping; + } + + debug("%s: %s carveout not found\n", dev->name, name); + return NULL; +} + UCLASS_DRIVER(rproc) = { .id = UCLASS_REMOTEPROC, .name = "remoteproc", @@ -688,6 +716,7 @@ static int alloc_vring(struct udevice *dev, struct fw_rsc_vdev *rsc, int i) static int handle_vdev(struct udevice *dev, struct fw_rsc_vdev *rsc, int offset, int avail) { + struct rproc *rproc; int i, ret; void *pa; @@ -720,7 +749,18 @@ static int handle_vdev(struct udevice *dev, struct fw_rsc_vdev *rsc, } /* - * allocate the vrings + * If virtio device creation is supported, then prefer to get vrings + * during find_vq op + */ + rproc = rproc_get_cfg(dev); + + if (rproc && rproc->support_rpmsg_virtio && + !(IS_ENABLED(CONFIG_SANDBOX))) { + return rproc_virtio_create_dev(dev, rsc, offset); + } + + /* + * allocate the vrings traditional way */ for (i = 0; i < rsc->num_of_vrings; i++) { ret = alloc_vring(dev, rsc, i); diff --git a/drivers/remoteproc/rproc_virtio.c b/drivers/remoteproc/rproc_virtio.c new file mode 100644 index 0000000000..5e7cdfa12f --- /dev/null +++ b/drivers/remoteproc/rproc_virtio.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Remote Processor Messaging transport + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2023, Advanced Micro Devices Inc. + * + * VirtIO RPMsg transport driver + * Ported from Linux drivers/remoteproc/remoteproc_virtio.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * rproc_flush_dcache() - flush shared memory regions + * @dev: valid remoteproc virtio device + * + * Some platforms have dcache enabled. If dcache is on then data written + * to shared memory is actually written to cache memory. This function + * checks if cache is on or not and if it is on, then it performs + * flush and invalidate operation on address range or reserved memory + * created by platform driver for remoteproc + * + * Return: none + */ +void rproc_flush_dcache(struct udevice *dev) +{ + struct rproc *rproc = rproc_get_cfg(dev->parent); + struct rproc_mem_entry *mapping = NULL; + struct list_head *mapping_node = NULL; + + /* If dcache is off, don't perform cache operation */ + if (dcache_status() == false) + return; + + /* + * If cache is on, then flush cache + * specially reserved mem regions for, + * resource table, vrings and vdevbuffer of platform dev + */ + list_for_each(mapping_node, &rproc->mappings.node) { + mapping = container_of(mapping_node, struct rproc_mem_entry, + node); + + /* + * First flush data so current data from cache is written + * to actual memory from cache. Then invalidate cache so + * next time data will be accessed from actual memory + */ + flush_dcache_range(mapping->da, mapping->da + mapping->len); + invalidate_dcache_range(mapping->da, mapping->da + mapping->len); + } +} + +int rproc_virtio_create_dev(struct udevice *parent, struct fw_rsc_vdev *rsc, + int offset) +{ + struct rproc_rvdev_data *rvdev_data; + struct udevice *vdev = NULL; + struct rproc *rproc; + char *dev_name; + int ret; + + rproc = rproc_get_cfg(parent); + if (!rproc) + return -EINVAL; + + rvdev_data = kzalloc(sizeof(*rvdev_data), GFP_KERNEL); + rvdev_data->id = rsc->id; + rvdev_data->rsc_offset = offset; + + dev_name = kcalloc(32, sizeof(char), GFP_KERNEL); + sprintf(dev_name, "rproc-virtio#%d", rproc->rproc_id); + + rvdev_data->index = rproc->rproc_id; + ret = device_bind(parent, DM_DRIVER_GET(rproc_virtio), + dev_name, rvdev_data, ofnode_null(), + &vdev); + if (ret) { + debug("failed to bind %s device\n", dev_name); + return ret; + } + + ret = device_probe(vdev); + if (ret) { + debug("probing device %s failed\n", dev_name); + return ret; + } + + free(dev_name); + dev_name = NULL; + + return 0; +} + +static int rproc_virtio_get_config(struct udevice *dev, unsigned int offset, + void *buf, unsigned int len) +{ + struct rproc_rvdev_data *rvdev_data; + struct fw_rsc_vdev *rsc; + struct rproc *rproc; + void *cfg; + + rvdev_data = dev_get_plat(dev); + rproc = rproc_get_cfg(dev->parent); + + rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset; + + /* flush cache before reading configurations */ + rproc_flush_dcache(dev); + + cfg = &rsc->vring[rsc->num_of_vrings]; + + if (offset + len > rsc->config_len || offset + len < len) { + dev_err(dev, "rproc_virtio_get: access out of bounds\n"); + return -EINVAL; + } + + memcpy(buf, cfg + offset, len); + + return 0; +} + +static void rproc_transport_features(struct udevice *dev) +{ + /* + * Packed ring isn't enabled on remoteproc for now, + * because remoteproc uses vring_new_virtqueue() which + * creates virtio rings on preallocated memory. + */ + __virtio_clear_bit(dev, VIRTIO_F_RING_PACKED); +} + +static int rproc_virtio_set_config(struct udevice *dev, unsigned int offset, + const void *buf, unsigned int len) +{ + struct rproc_rvdev_data *rvdev_data; + struct fw_rsc_vdev *rsc; + struct rproc *rproc; + void *cfg; + + rvdev_data = dev_get_plat(dev); + rproc = rproc_get_cfg(dev->parent); + + rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset; + cfg = &rsc->vring[rsc->num_of_vrings]; + + if (offset + len > rsc->config_len || offset + len < len) { + dev_err(dev, "rproc_virtio_set: access out of bounds\n"); + return -EINVAL; + } + + memcpy(cfg + offset, buf, len); + rproc_flush_dcache(dev); + + return 0; +} + +static int rproc_virtio_get_status(struct udevice *dev, u8 *status) +{ + struct rproc_rvdev_data *rvdev_data; + struct fw_rsc_vdev *rsc; + struct rproc *rproc; + + rvdev_data = dev_get_plat(dev); + rproc = rproc_get_cfg(dev->parent); + + rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset; + + *status = rsc->status; + + rproc_flush_dcache(dev); + + return 0; +} + +static int rproc_virtio_set_status(struct udevice *dev, u8 status) +{ + struct rproc_rvdev_data *rvdev_data; + struct fw_rsc_vdev *rsc; + struct rproc *rproc; + + rvdev_data = dev_get_plat(dev); + rproc = rproc_get_cfg(dev->parent); + + rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset; + + rsc->status = status; + + rproc_flush_dcache(dev); + + return 0; +} + +static int rproc_virtio_reset(struct udevice *dev) +{ + struct rproc_rvdev_data *rvdev_data; + struct fw_rsc_vdev *rsc; + struct rproc *rproc; + + rvdev_data = dev_get_plat(dev); + rproc = rproc_get_cfg(dev->parent); + + rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset; + + rsc->status = 0; + + rproc_flush_dcache(dev); + + return 0; +} + +static int rproc_virtio_get_features(struct udevice *dev, u64 *features) +{ + struct rproc_rvdev_data *rvdev_data; + struct fw_rsc_vdev *rsc; + struct rproc *rproc; + + rvdev_data = dev_get_plat(dev); + rproc = rproc_get_cfg(dev->parent); + + rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset; + + rproc_flush_dcache(dev); + + *features = rsc->dfeatures; + + return 0; +} + +static int rproc_virtio_set_features(struct udevice *dev) +{ + struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct rproc_rvdev_data *rvdev_data; + struct fw_rsc_vdev *rsc; + struct rproc *rproc; + + rvdev_data = dev_get_plat(dev); + rproc = rproc_get_cfg(dev->parent); + + rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset; + + /* Give virtio_rproc a chance to accept features. */ + rproc_transport_features(dev); + + /* reject any features > 32 bits! */ + if (WARN_ON((u32)uc_priv->features != uc_priv->features)) + return -EINVAL; + + /* + * Remember the finalized features of our vdev, and provide it + * to the remote processor once it is powered on. + */ + rsc->gfeatures = uc_priv->features; + + rproc_flush_dcache(dev); + + return 0; +} + +static void rproc_virtio_del_vq(struct virtqueue *vq) +{ + vring_del_virtqueue(vq); +} + +static int rproc_virtio_del_vqs(struct udevice *vdev) +{ + struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(vdev); + struct virtqueue *vq, *n; + + list_for_each_entry_safe(vq, n, &uc_priv->vqs, list) + rproc_virtio_del_vq(vq); + + return 0; +} + +static int rproc_virtio_find_vqs(struct udevice *vdev, unsigned int nvqs, + struct virtqueue *vqs[]) +{ + int queue_index = 0, align, i, core_id, da; + struct rproc_rvdev_data *rvdev_data; + struct fw_rsc_vdev_vring *rvring; + struct rproc_mem_entry *mapping; + struct fw_rsc_vdev *rsc; + char name[32] = {0}; + struct rproc *rproc; + struct vring vring; + unsigned int num; + + rvdev_data = dev_get_plat(vdev); + rproc = rproc_get_cfg(vdev->parent); + + if (nvqs > 2) + return -EINVAL; + + core_id = rvdev_data->index; + + rsc = (void *)rproc->table_ptr + rvdev_data->rsc_offset; + + for (i = 0; i < nvqs; i++) { + sprintf(name, "vdev%dvring%d", core_id, i); + mapping = rproc_find_res_by_name(vdev->parent, name); + if (!mapping) { + dev_err(vdev, "carveout %s not found\n", name); + return -EINVAL; + } + + num = rsc->vring[i].num; + /* assume num is a power of 2 */ + if (num & (num - 1)) { + dev_err(vdev, "Bad virtqueue length %u\n", num); + return -EINVAL; + } + + align = rsc->vring[i].align; + rvring = &rvdev_data->vring[i]; + + memset(mapping->va, 0, vring_size(num, align)); + vring_init(&vring, num, mapping->va, align, NULL); + + vqs[i] = vring_new_virtqueue(queue_index, vring, vdev); + if (!vqs[i]) { + dev_err(vdev, "failed to create vq\n"); + return -EINVAL; + } + + rvring->da = da; + rvring->notifyid = vqs[i]->index; + rvring->num = num; + rvring->align = align; + + /* update vring in resource table */ + rsc->vring[i].notifyid = rvring->notifyid; + rsc->vring[i].da = mapping->da; + rsc->vring[i].pa = mapping->da; + queue_index++; + + rproc_flush_dcache(vdev); + } + + return 0; +} + +static int rproc_virtio_notify(struct udevice *dev, struct virtqueue *vq) +{ + struct dm_rproc_ops *ops; + + ops = rproc_get_ops(dev->parent); + if (!ops || !ops->kick) { + dev_err(dev, "kick op not available for dev %s\n", + dev->parent->name); + return -EINVAL; + } + + rproc_flush_dcache(dev); + + return ops->kick(dev->parent, vq->index); +} + +static int rproc_virtio_probe(struct udevice *vdev) +{ + struct virtio_dev_priv *ucpriv = dev_get_uclass_priv(vdev); + struct rproc_rvdev_data *rvdev_data; + struct udevice *rproc_dev; + char rvdev_name[32] = {0}; + + rvdev_data = dev_get_plat(vdev); + + rproc_dev = vdev->parent; + + sprintf(rvdev_name, "vdev%dbuffer", rvdev_data->index); + rvdev_data->vdev_buf = rproc_find_res_by_name(vdev->parent, rvdev_name); + if (!rvdev_data->vdev_buf) { + dev_err(vdev, "%s carveout not found", rvdev_name); + return -EINVAL; + } + + ucpriv->vdev = vdev; + ucpriv->device = rvdev_data->id; + + return 0; +} + +static const struct dm_virtio_ops rproc_virtio_ops = { + .get_config = rproc_virtio_get_config, + .set_config = rproc_virtio_set_config, + .get_status = rproc_virtio_get_status, + .set_status = rproc_virtio_set_status, + .reset = rproc_virtio_reset, + .get_features = rproc_virtio_get_features, + .set_features = rproc_virtio_set_features, + .find_vqs = rproc_virtio_find_vqs, + .del_vqs = rproc_virtio_del_vqs, + .notify = rproc_virtio_notify, +}; + +static const struct udevice_id rproc_virtio_ids[] = { + { .compatible = "rproc,virtio" }, +}; + +U_BOOT_DRIVER(rproc_virtio) = { + .name = "rproc_virtio", + .id = UCLASS_VIRTIO, + .of_match = rproc_virtio_ids, + .ops = &rproc_virtio_ops, + .probe = rproc_virtio_probe, + .plat_auto = sizeof(struct rproc_rvdev_data), +}; diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index c9adcce5c0..4a9645fac4 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -331,6 +331,22 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index, return vq; } +struct virtqueue *vring_new_virtqueue(unsigned int index, + struct vring vring, + struct udevice *udev) +{ + struct virtqueue *vq; + + vq = __vring_new_virtqueue(index, vring, udev); + if (!vq) + return NULL; + + debug("(%s): created vring @ %p for vq @ %p\n", udev->name, + vring.desc, vq); + + return vq; +} + struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, unsigned int vring_align, struct udevice *udev) diff --git a/include/remoteproc.h b/include/remoteproc.h index af5c584e6e..4251af52bd 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -343,25 +343,20 @@ enum rproc_crash_type { #define RPMSG_TOTAL_BUF_SPACE (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE) /** - * struct rproc_vring - remoteproc vring state - * @va: virtual address - * @dma: dma address - * @len: length, in bytes - * @da: device address - * @align: vring alignment - * @notifyid: rproc-specific unique vring index - * @rvdev: remote vdev - * @vq: the virtqueue of this vring - */ -struct rproc_vring { - void *va; - dma_addr_t dma; - int len; - u32 da; - u32 align; - int notifyid; - struct rproc_vdev *rvdev; - struct virtqueue *vq; + * struct rproc_rvdev_data - remoteproc virito device data + * + * @rsc_offset: resource offset + * @id: virtio dev id + * @index: vdev position vs other vdev declared in resource table + * @vring: store tx and rx vrings description + * @vdev_buf: vdev0buffer carveout mapping + */ +struct rproc_rvdev_data { + u32 rsc_offset; + unsigned int id; + u32 index; + struct fw_rsc_vdev_vring vring[2]; + struct rproc_mem_entry *vdev_buf; }; /** struct rproc - structure with all processor specific information for @@ -383,6 +378,7 @@ struct rproc_vring { * * @entry_point: address that is the entry point for the remote core. This * address is in the memory view of the remotecore. + * @rproc_id: per core id * * @load_addr: Address to which the bootloader loads the firmware from * persistent storage before invoking the ELF loader. Keeping this address @@ -393,6 +389,11 @@ struct rproc_vring { * @firmware_name: Name of the file that is expected to contain the ELF image. * * @has_rsc_table: Flag populated after parsing the ELF binary on target. + * @support_rpmsg_virtio: set in rproc platform driver to support new rpmsg framework + * @mappings: list of reserved memory regions created by platform driver + * such as vring0, vring1, vdevbuffer etc... + * @table_ptr: holds address of resource table from shared memory between host + * and remote processors */ struct rproc { @@ -403,6 +404,7 @@ struct rproc { unsigned long mmu_base_addr[2]; unsigned long load_addr; unsigned long entry_point; + int rproc_id; char *core_name; char *firmware_name; char *ptn; @@ -414,6 +416,9 @@ struct rproc { struct rproc_intmem_to_l3_mapping *intmem_to_l3_mapping; u32 trace_pa; u32 trace_len; + bool support_rpmsg_virtio; + struct rproc_mem_entry mappings; + struct resource_table *table_ptr; }; extern struct rproc *rproc_cfg_arr[2]; @@ -444,6 +449,7 @@ struct dm_rproc_uclass_pdata { const char *name; enum rproc_mem_type mem_type; void *driver_plat_data; + struct rproc *rproc; }; /** @@ -534,10 +540,22 @@ struct dm_rproc_ops { unsigned long align); unsigned int (*config_pagetable)(struct udevice *dev, unsigned int virt, unsigned int phys, unsigned int len); + struct resource_table *(*get_loaded_rsc_table)(struct udevice *dev, + int *tablesz); + /** + * kick() - kick the remote device for communication (needed for rpmsg) + * + * @dev: Remote proc device + * @notify_id: vq id to be notified + * @return 0 on success, 1 if not responding, -ve on other errors. + */ + int (*kick)(struct udevice *dev, int notify_id); }; /* Accessor */ #define rproc_get_ops(dev) ((struct dm_rproc_ops *)(dev)->driver->ops) +#define rproc_get_cfg(dev) (((struct dm_rproc_uclass_pdata *) \ + dev_get_plat(dev))->rproc) #if CONFIG_IS_ENABLED(REMOTEPROC) /** @@ -737,6 +755,10 @@ unsigned long rproc_parse_resource_table(struct udevice *dev, struct resource_table *rproc_find_resource_table(struct udevice *dev, unsigned int addr, int *tablesz); +struct resource_table *rproc_get_loaded_rsc_table(struct udevice *dev, + struct rproc *cfg); +struct rproc_mem_entry *rproc_find_res_by_name(struct udevice *dev, + const char *name); #else static inline int rproc_init(void) { return -ENOSYS; } static inline int rproc_dev_init(int id) { return -ENOSYS; } @@ -776,6 +798,12 @@ static inline int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr, ulong fw_size, ulong *rsc_addr, ulong *rsc_size) { return -ENOSYS; } + +static inline struct rproc_mem_entry *rproc_find_res_by_name(struct udevice *dev, + const char *name) +{ + return NULL; +} #endif #endif /* _RPROC_H_ */ diff --git a/include/rproc_virtio.h b/include/rproc_virtio.h new file mode 100644 index 0000000000..cbe8ff420f --- /dev/null +++ b/include/rproc_virtio.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023, Advanced Micro Devices Inc. + */ + +#ifndef _RPROC_VIRTIO_H_ +#define _RPROC_VIRTIO_H_ + +#include +#include + +void rproc_flush_dcache(struct udevice *dev); + +#ifndef CONFIG_SANDBOX + +int rproc_virtio_create_dev(struct udevice *parent, struct fw_rsc_vdev *rsc, + int offset); + +#else + +int rproc_virtio_create_dev(struct udevice *parent, struct fw_rsc_vdev *rsc, + int offset) +{ + return -ENODEV; +} + +#endif /* CONFIG_SANDBOX */ + +#endif /* _RPROC_VIRTIO_H_ */ diff --git a/include/virtio.h b/include/virtio.h index 062a24630c..16d0f8aa7f 100644 --- a/include/virtio.h +++ b/include/virtio.h @@ -69,6 +69,9 @@ /* v1.0 compliant */ #define VIRTIO_F_VERSION_1 32 +/* packed virtqueue layout */ +#define VIRTIO_F_RING_PACKED 34 + /* * If clear - device has the IOMMU bypass quirk feature. * If set - use platform tools to detect the IOMMU. diff --git a/include/virtio_ring.h b/include/virtio_ring.h index e8e91044a2..4a9b4078ee 100644 --- a/include/virtio_ring.h +++ b/include/virtio_ring.h @@ -2,6 +2,7 @@ /* * Copyright (C) 2018, Tuomas Tynkkynen * Copyright (C) 2018, Bin Meng + * Copyright (C) 2023, Advanced Micro Devices Inc. * * From Linux kernel include/uapi/linux/virtio_ring.h */ @@ -227,6 +228,22 @@ void virtqueue_kick(struct virtqueue *vq); */ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len); +/** + * vring_new_virtqueue - create a virtqueue at user defined vring address + * + * @index: the index of the queue + * @vring: vring created at user defined address + * @udev: the virtio transport udevice + * @return: the virtqueue pointer or NULL if failed + * + * This creates a virtqueue using vring address decided by the user of API + * + * This API is supposed to be called by the virtio transport driver in the + * virtio find_vqs() uclass method. + */ +struct virtqueue *vring_new_virtqueue(unsigned int index, struct vring vring, + struct udevice *udev); + /** * vring_create_virtqueue - create a virtqueue for a virtio device *