From patchwork Wed May 5 09:38:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 12239499 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 27EB3C4361B for ; Wed, 5 May 2021 09:42:36 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 94365613F1 for ; Wed, 5 May 2021 09:42:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 94365613F1 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=E/VLULHa1UmUokaInz1EkLSH/AoIWAhwoFftVfcwmS8=; b=SJ3Uj8NtaBsKEAGtgS9A9Njz4 O63tI9B4FPRBJGUo0ahuzJoSVYj5Bzz46cogvGTuw7Cx0jJ1ki+1m46P73CWgwytAhVehqc91m7BR Ykr0fXAVfSw4ErxFeVmIu2BACQfMpJTMlKfkjumagjiFju0oAR4p4GZks+JBZCH/COVHCjfL9Hsl+ LWEsQkzGoZvjGgkLE0Xd+ccnBm7wz3CsjdyPHbrtWbidNm28YTBnxVuTeO8RQeS1PJF4cPZDO9NJ9 BSQLPE3VwkumkYNKD4OY/Edr5Qi8CxEVTXhFBV0EU1GROSvFWeTdNwh1JPsXojIMTxzTW9lNP+OJL Vl8ym/bLQ==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1leE0V-000k5S-GT; Wed, 05 May 2021 09:39:53 +0000 Received: from bombadil.infradead.org ([2607:7c80:54:e::133]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1leDzm-000jyj-47 for linux-arm-kernel@desiato.infradead.org; Wed, 05 May 2021 09:39:06 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender :Reply-To:Content-Type:Content-ID:Content-Description; bh=e57Uz7xhPAZGLO0wZBajLOVVbHelsez71RfHOl6N/Zg=; b=vyOT2Nd6R7VUXwFAl5W7cqwMpU ZcLeLVIWbGh7ZGp0aPoy9zuv79YdJiLoVSL+s/dcp9YFUSufooAMgNSySZM9B5ogTR1369wcReudo yIlzhDHmjCjUdtStvS4/Yt5m8PGgRJpXb76dcaLSdwZdjbOZxNgwQk0esWJK82N1fvfZxuvv80MdX 1lEqmHGKGJes22Z21c3kzafK+IWjkaMTtrQk7c4HrrRaSrQgdzhIgeHjf0iLtUPNCRDeaP2dimJVF ksxPw8PI3IMBJy6iKtbys6zmDw4cT2TWstW6Rbv6zf1Ov8wCAvsReakwuOOjeNptu7/6wgmMi/8eK B5RckFRA==; Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1leDzh-004cQi-PL for linux-arm-kernel@lists.infradead.org; Wed, 05 May 2021 09:39:04 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E264311FB; Wed, 5 May 2021 02:38:58 -0700 (PDT) Received: from usa.arm.com (e103737-lin.cambridge.arm.com [10.1.197.49]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 8E9223F70D; Wed, 5 May 2021 02:38:57 -0700 (PDT) From: Sudeep Holla To: linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org Cc: Sudeep Holla , arve@google.com, Andrew Walbran , David Hartley , Achin Gupta , Jens Wiklander , Arunachalam Ganapathy , Marc Bonnici Subject: [PATCH v6 2/6] firmware: arm_ffa: Add initial FFA bus support for device enumeration Date: Wed, 5 May 2021 10:38:39 +0100 Message-Id: <20210505093843.3308691-3-sudeep.holla@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210505093843.3308691-1-sudeep.holla@arm.com> References: <20210505093843.3308691-1-sudeep.holla@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210505_023901_964597_42BBA869 X-CRM114-Status: GOOD ( 26.94 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The Arm FF for Armv8-A specification has concept of endpoints or partitions. In the Normal world, a partition could be a VM when the Virtualization extension is enabled or the kernel itself. In order to handle multiple partitions, we can create a FFA device for each such partition on a dedicated FFA bus. Similarly, different drivers requiring FFA transport can be registered on the same bus. We can match the device and drivers using UUID. This is mostly for the in-kernel users with FFA drivers. Signed-off-by: Sudeep Holla --- MAINTAINERS | 7 + drivers/firmware/Kconfig | 1 + drivers/firmware/Makefile | 1 + drivers/firmware/arm_ffa/Kconfig | 16 +++ drivers/firmware/arm_ffa/Makefile | 4 + drivers/firmware/arm_ffa/bus.c | 207 ++++++++++++++++++++++++++++++ include/linux/arm_ffa.h | 91 +++++++++++++ 7 files changed, 327 insertions(+) create mode 100644 drivers/firmware/arm_ffa/Kconfig create mode 100644 drivers/firmware/arm_ffa/Makefile create mode 100644 drivers/firmware/arm_ffa/bus.c create mode 100644 include/linux/arm_ffa.h diff --git a/MAINTAINERS b/MAINTAINERS index 121b1a12384a..88a988e08d11 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7052,6 +7052,13 @@ F: include/linux/firewire.h F: include/uapi/linux/firewire*.h F: tools/firewire/ +FIRMWARE FRAMEWORK FOR ARMV8-A +M: Sudeep Holla +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: drivers/firmware/arm_ffa/ +F: include/linux/arm_ffa.h + FIRMWARE LOADER (request_firmware) M: Luis Chamberlain L: linux-kernel@vger.kernel.org diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index db0ea2d2d75a..b53ac9fc7704 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -296,6 +296,7 @@ config TURRIS_MOX_RWTM other manufacturing data and also utilize the Entropy Bit Generator for hardware random number generation. +source "drivers/firmware/arm_ffa/Kconfig" source "drivers/firmware/broadcom/Kconfig" source "drivers/firmware/google/Kconfig" source "drivers/firmware/efi/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 5e013b6a3692..546ac8e7f6d0 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o +obj-y += arm_ffa/ obj-y += arm_scmi/ obj-y += broadcom/ obj-y += meson/ diff --git a/drivers/firmware/arm_ffa/Kconfig b/drivers/firmware/arm_ffa/Kconfig new file mode 100644 index 000000000000..261a3660650a --- /dev/null +++ b/drivers/firmware/arm_ffa/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only +config ARM_FFA_TRANSPORT + tristate "Arm Firmware Framework for Armv8-A" + depends on OF + depends on ARM64 + default n + help + This Firmware Framework(FF) for Arm A-profile processors describes + interfaces that standardize communication between the various + software images which includes communication between images in + the Secure world and Normal world. It also leverages the + virtualization extension to isolate software images provided + by an ecosystem of vendors from each other. + + This driver provides interface for all the client drivers making + use of the features offered by ARM FF-A. diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile new file mode 100644 index 000000000000..bfe4323a8784 --- /dev/null +++ b/drivers/firmware/arm_ffa/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +ffa-bus-y = bus.o +ffa-module-objs := $(ffa-bus-y) +obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-module.o diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c new file mode 100644 index 000000000000..b743fb2256e9 --- /dev/null +++ b/drivers/firmware/arm_ffa/bus.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 ARM Ltd. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +static int ffa_device_match(struct device *dev, struct device_driver *drv) +{ + const struct ffa_device_id *id_table; + struct ffa_device *ffa_dev; + + id_table = to_ffa_driver(drv)->id_table; + ffa_dev = to_ffa_dev(dev); + + while (!uuid_is_null(&id_table->uuid)) { + if (uuid_equal(&ffa_dev->uuid, &id_table->uuid)) + return 1; + id_table++; + } + + return 0; +} + +static int ffa_device_probe(struct device *dev) +{ + struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver); + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + if (!ffa_device_match(dev, dev->driver)) + return -ENODEV; + + return ffa_drv->probe(ffa_dev); +} + +static int ffa_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb", + ffa_dev->vm_id, &ffa_dev->uuid); +} + +static ssize_t partition_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + return sprintf(buf, "0x%04x\n", ffa_dev->vm_id); +} +static DEVICE_ATTR_RO(partition_id); + +static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + return sprintf(buf, "%pUb\n", &ffa_dev->uuid); +} +static DEVICE_ATTR_RO(uuid); + +static struct attribute *ffa_device_attributes_attrs[] = { + &dev_attr_partition_id.attr, + &dev_attr_uuid.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ffa_device_attributes); + +struct bus_type ffa_bus_type = { + .name = "arm_ffa", + .match = ffa_device_match, + .probe = ffa_device_probe, + .uevent = ffa_device_uevent, + .dev_groups = ffa_device_attributes_groups, +}; +EXPORT_SYMBOL_GPL(ffa_bus_type); + +int ffa_driver_register(struct ffa_driver *driver, struct module *owner, + const char *mod_name) +{ + int ret; + + driver->driver.bus = &ffa_bus_type; + driver->driver.name = driver->name; + driver->driver.owner = owner; + driver->driver.mod_name = mod_name; + + ret = driver_register(&driver->driver); + if (!ret) + pr_debug("registered new ffa driver %s\n", driver->name); + + return ret; +} +EXPORT_SYMBOL_GPL(ffa_driver_register); + +void ffa_driver_unregister(struct ffa_driver *driver) +{ + driver_unregister(&driver->driver); +} +EXPORT_SYMBOL_GPL(ffa_driver_unregister); + +static void ffa_release_device(struct device *dev) +{ + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + kfree(ffa_dev); +} + +static int __ffa_devices_unregister(struct device *dev, void *data) +{ + ffa_release_device(dev); + + return 0; +} + +static void ffa_devices_unregister(void) +{ + bus_for_each_dev(&ffa_bus_type, NULL, NULL, + __ffa_devices_unregister); +} + +bool ffa_device_is_valid(struct ffa_device *ffa_dev) +{ + bool valid = false; + struct device *dev = NULL; + struct ffa_device *tmp_dev; + + do { + dev = bus_find_next_device(&ffa_bus_type, dev); + tmp_dev = to_ffa_dev(dev); + if (tmp_dev == ffa_dev) { + valid = true; + break; + } + put_device(dev); + } while (dev); + + put_device(dev); + + return valid; +} + +struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id) +{ + int ret; + struct device *dev; + struct ffa_device *ffa_dev; + + ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL); + if (!ffa_dev) + return NULL; + + dev = &ffa_dev->dev; + dev->bus = &ffa_bus_type; + dev->release = ffa_release_device; + dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id); + + ffa_dev->vm_id = vm_id; + uuid_copy(&ffa_dev->uuid, uuid); + + ret = device_register(&ffa_dev->dev); + if (ret) { + dev_err(dev, "unable to register device %s err=%d\n", + dev_name(dev), ret); + put_device(dev); + return NULL; + } + + return ffa_dev; +} +EXPORT_SYMBOL_GPL(ffa_device_register); + +void ffa_device_unregister(struct ffa_device *ffa_dev) +{ + if (!ffa_dev) + return; + + device_unregister(&ffa_dev->dev); +} +EXPORT_SYMBOL_GPL(ffa_device_unregister); + +static int __init arm_ffa_bus_init(void) +{ + return bus_register(&ffa_bus_type); +} +module_init(arm_ffa_bus_init); + +static void __exit arm_ffa_bus_exit(void) +{ + ffa_devices_unregister(); + bus_unregister(&ffa_bus_type); +} + +module_exit(arm_ffa_bus_exit); + +MODULE_ALIAS("arm-ffa-bus"); +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("Arm FF-A bus driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h new file mode 100644 index 000000000000..aaff89364541 --- /dev/null +++ b/include/linux/arm_ffa.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 ARM Ltd. + */ + +#ifndef _LINUX_ARM_FFA_H +#define _LINUX_ARM_FFA_H + +#include +#include +#include +#include +#include + +/* FFA Bus/Device/Driver related */ +struct ffa_device { + int vm_id; + uuid_t uuid; + struct device dev; +}; + +#define to_ffa_dev(d) container_of(d, struct ffa_device, dev) + +struct ffa_device_id { + uuid_t uuid; +}; + +struct ffa_driver { + const char *name; + int (*probe)(struct ffa_device *sdev); + void (*remove)(struct ffa_device *sdev); + const struct ffa_device_id *id_table; + + struct device_driver driver; +}; + +#define to_ffa_driver(d) container_of(d, struct ffa_driver, driver) + +static inline void ffa_dev_set_drvdata(struct ffa_device *fdev, void *data) +{ + fdev->dev.driver_data = data; +} + +#if IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT) +struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id); +void ffa_device_unregister(struct ffa_device *ffa_dev); +int ffa_driver_register(struct ffa_driver *driver, struct module *owner, + const char *mod_name); +void ffa_driver_unregister(struct ffa_driver *driver); +bool ffa_device_is_valid(struct ffa_device *ffa_dev); + +#else +static inline +struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id) +{ + return NULL; +} + +static inline void ffa_device_unregister(struct ffa_device *dev) {} + +static inline int +ffa_driver_register(struct ffa_driver *driver, struct module *owner, + const char *mod_name) +{ + return -EINVAL; +} + +static inline void ffa_driver_unregister(struct ffa_driver *driver) {} + +static inline +bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; } + +#endif /* CONFIG_ARM_FFA_TRANSPORT */ + +#define ffa_register(driver) \ + ffa_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) +#define ffa_unregister(driver) \ + ffa_driver_unregister(driver) + +/** + * module_ffa_driver() - Helper macro for registering a psa_ffa driver + * @__ffa_driver: ffa_driver structure + * + * Helper macro for psa_ffa drivers to set up proper module init / exit + * functions. Replaces module_init() and module_exit() and keeps people from + * printing pointless things to the kernel log when their driver is loaded. + */ +#define module_ffa_driver(__ffa_driver) \ + module_driver(__ffa_driver, ffa_register, ffa_unregister) + +#endif /* _LINUX_ARM_FFA_H */