All of lore.kernel.org
 help / color / mirror / Atom feed
From: Fuad Tabba <tabba@google.com>
To: Sudeep Holla <sudeep.holla@arm.com>
Cc: linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
	kernel-team@android.com, Will Deacon <will@kernel.org>,
	tsoni@quicinc.com, pratikp@quicinc.com
Subject: Re: [PATCH 6/9] firmware: arm_ffa: Add initial Arm FFA driver support
Date: Mon, 7 Sep 2020 08:55:13 +0100	[thread overview]
Message-ID: <CA+EHjTwYm--tOGjFq0aqP_bsBPu+f1hGTYrVxsuqLw-4K+QJMA@mail.gmail.com> (raw)
In-Reply-To: <20200829170923.29949-7-sudeep.holla@arm.com>

Hi Sudeep,

I understand that this is an RFC, but I have a few suggestions about
how the FF-A interface code might be structured.  See below.

On Sat, Aug 29, 2020 at 6:09 PM Sudeep Holla <sudeep.holla@arm.com> wrote:
>
> This just add a basic driver that sets up the transport(e.g. SMCCC),
> checks the FFA version implemented, get the partition ID for self and
> sets up the Tx/Rx buffers for communication.
>
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> ---
>  drivers/firmware/arm_ffa/Makefile |   3 +-
>  drivers/firmware/arm_ffa/common.h |  23 +++
>  drivers/firmware/arm_ffa/driver.c | 288 ++++++++++++++++++++++++++++++
>  3 files changed, 313 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/firmware/arm_ffa/common.h
>  create mode 100644 drivers/firmware/arm_ffa/driver.c
>
> diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile
> index fadb325ee888..1a9bd2bf8752 100644
> --- a/drivers/firmware/arm_ffa/Makefile
> +++ b/drivers/firmware/arm_ffa/Makefile
> @@ -1,3 +1,4 @@
>  # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-bus.o
> +obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-bus.o ffa-driver.o
>  ffa-bus-y = bus.o
> +ffa-driver-y = driver.o
> diff --git a/drivers/firmware/arm_ffa/common.h b/drivers/firmware/arm_ffa/common.h
> new file mode 100644
> index 000000000000..720c8425dfd6
> --- /dev/null
> +++ b/drivers/firmware/arm_ffa/common.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020 ARM Ltd.
> + */
> +
> +#ifndef _FFA_COMMON_H
> +#define _FFA_COMMON_H
> +
> +#include <linux/arm-smccc.h>
> +#include <linux/err.h>
> +
> +typedef struct arm_smccc_v1_2_res ffa_res_t;
> +
> +typedef ffa_res_t
> +(ffa_fn)(unsigned long, unsigned long, unsigned long, unsigned long,
> +        unsigned long, unsigned long, unsigned long, unsigned long);
> +
> +static inline int __init ffa_transport_init(ffa_fn **invoke_ffa_fn)
> +{
> +       return -EOPNOTSUPP;
> +}
> +
> +#endif /* _FFA_COMMON_H */
> diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
> new file mode 100644
> index 000000000000..3670ba400f89
> --- /dev/null
> +++ b/drivers/firmware/arm_ffa/driver.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Arm Firmware Framework for ARMv8-A(FFA) interface driver
> + *
> + * The Arm FFA specification[1] describes a software architecture to
> + * leverages the virtualization extension to isolate software images
> + * provided by an ecosystem of vendors from each other and describes
> + * interfaces that standardize communication between the various software
> + * images including communication between images in the Secure world and
> + * Normal world. Any Hypervisor could use the FFA interfaces to enable
> + * communication between VMs it manages.
> + *
> + * The Hypervisor a.k.a Partition managers in FFA terminology can assign
> + * system resources(Memory regions, Devices, CPU cycles) to the partitions
> + * and manage isolation amongst them.
> + *
> + * [1] https://developer.arm.com/docs/den0077/latest
> + *
> + * Copyright (C) 2020 Arm Ltd.
> + */
> +
> +#define DRIVER_NAME "ARM FF-A"
> +#define pr_fmt(fmt) DRIVER_NAME ": " fmt
> +
> +#include <linux/bitfield.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/arm_ffa.h>
> +
> +#include "common.h"
> +
> +#define FFA_SMC(calling_convention, func_num)                          \
> +       ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention),   \
> +                          ARM_SMCCC_OWNER_STANDARD, (func_num))
> +
> +#define FFA_SMC_32(func_num)   FFA_SMC(ARM_SMCCC_SMC_32, (func_num))
> +#define FFA_SMC_64(func_num)   FFA_SMC(ARM_SMCCC_SMC_64, (func_num))
> +
> +#define FFA_ERROR                      FFA_SMC_32(0x60)
> +#define FFA_SUCCESS                    FFA_SMC_32(0x61)
> +#define FFA_INTERRUPT                  FFA_SMC_32(0x62)
> +#define FFA_VERSION                    FFA_SMC_32(0x63)
> +#define FFA_FEATURES                   FFA_SMC_32(0x64)
> +#define FFA_RX_RELEASE                 FFA_SMC_32(0x65)
> +#define FFA_RXTX_MAP                   FFA_SMC_32(0x66)
> +#define FFA_RXTX_UNMAP                 FFA_SMC_32(0x67)
> +#define FFA_PARTITION_INFO_GET         FFA_SMC_32(0x68)
> +#define FFA_ID_GET                     FFA_SMC_32(0x69)
> +#define FFA_MSG_POLL                   FFA_SMC_32(0x6A)
> +#define FFA_MSG_WAIT                   FFA_SMC_32(0x6B)
> +#define FFA_YIELD                      FFA_SMC_32(0x6C)
> +#define FFA_RUN                                FFA_SMC_32(0x6D)
> +#define FFA_MSG_SEND                   FFA_SMC_32(0x6E)
> +#define FFA_MSG_SEND_DIRECT_REQ                FFA_SMC_32(0x6F)
> +#define FFA_FN64_MSG_SEND_DIRECT_REQ   FFA_SMC_64(0x6F)
> +#define FFA_MSG_SEND_DIRECT_RESP       FFA_SMC_32(0x70)
> +#define FFA_FN64_MSG_SEND_DIRECT_RESP  FFA_SMC_64(0x70)
> +#define FFA_MEM_DONATE                 FFA_SMC_32(0x71)
> +#define FFA_FN64_MEM_DONATE            FFA_SMC_32(0x71)
> +#define FFA_MEM_LEND                   FFA_SMC_32(0x72)
> +#define FFA_FN64_MEM_LEND              FFA_SMC_32(0x72)
> +#define FFA_MEM_SHARE                  FFA_SMC_32(0x73)
> +#define FFA_FN64_MEM_SHARE             FFA_SMC_64(0x73)
> +#define FFA_MEM_RETRIEVE_REQ           FFA_SMC_32(0x74)
> +#define FFA_FN64_MEM_RETRIEVE_REQ      FFA_SMC_64(0x74)
> +#define FFA_MEM_RETRIEVE_RESP          FFA_SMC_32(0x75)
> +#define FFA_MEM_RELINQUISH             FFA_SMC_32(0x76)
> +#define FFA_MEM_RECLAIM                        FFA_SMC_32(0x77)
> +#define FFA_MEM_OP_PAUSE               FFA_SMC_32(0x78)
> +#define FFA_MEM_OP_RESUME              FFA_SMC_32(0x79)
> +#define FFA_MEM_FRAG_RX                        FFA_SMC_32(0x7A)
> +#define FFA_MEM_FRAG_TX                        FFA_SMC_32(0x7B)
> +#define FFA_NORMAL_WORLD_RESUME                FFA_SMC_32(0x7C)
> +
> +/*
> + * For some calls it is necessary to use SMC64 to pass or return 64-bit values.
> + * For such calls FFA_FN_NATIVE(name) will choose the appropriate
> + * (native-width) function ID.
> + */
> +#ifdef CONFIG_64BIT
> +#define FFA_FN_NATIVE(name)    FFA_FN64_##name
> +#else
> +#define FFA_FN_NATIVE(name)    FFA_##name
> +#endif
> +
> +/* FFA error codes. */
> +#define FFA_RET_SUCCESS            (0)
> +#define FFA_RET_NOT_SUPPORTED      (-1)
> +#define FFA_RET_INVALID_PARAMETERS (-2)
> +#define FFA_RET_NO_MEMORY          (-3)
> +#define FFA_RET_BUSY               (-4)
> +#define FFA_RET_INTERRUPTED        (-5)
> +#define FFA_RET_DENIED             (-6)
> +#define FFA_RET_RETRY              (-7)
> +#define FFA_RET_ABORTED            (-8)
> +
> +#define MAJOR_VERSION_MASK     GENMASK(30, 16)
> +#define MINOR_VERSION_MASK     GENMASK(15, 0)
> +#define MAJOR_VERSION(x)       (u16)(FIELD_GET(MAJOR_VERSION_MASK, (x)))
> +#define MINOR_VERSION(x)       (u16)(FIELD_GET(MINOR_VERSION_MASK, (x)))
> +#define PACK_VERSION_INFO(major, minor)                        \
> +       (FIELD_PREP(MAJOR_VERSION_MASK, (major)) |      \
> +        FIELD_PREP(MINOR_VERSION_MASK, (minor)))
> +#define FFA_VERSION_1_0        PACK_VERSION_INFO(1, 0)
> +#define FFA_MIN_VERSION        FFA_VERSION_1_0
> +#define FFA_DRIVER_VERSION     FFA_VERSION_1_0
> +
> +#define SENDER_ID_MASK         GENMASK(31, 16)
> +#define RECEIVER_ID_MASK       GENMASK(15, 0)
> +#define SENDER_ID(x)           (u16)(FIELD_GET(SENDER_ID_MASK, (x)))
> +#define RECEIVER_ID(x)         (u16)(FIELD_GET(RECEIVER_ID_MASK, (x)))
> +#define PACK_TARGET_INFO(s, r)         \
> +       (FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r)))
> +
> +/**
> + * FF-A specification mentions explicitly about '4K pages'. This should
> + * not be confused with the kernel PAGE_SIZE, which is the translation
> + * granule kernel is configured and may be one among 4K, 16K and 64K.
> + */
> +#define FFA_PAGE_SIZE          SZ_4K
> +/* Keeping RX TX buffer size as 64K for now */
> +#define RXTX_BUFFER_SIZE       SZ_64K

The code/definitions above will be reused in other parts that deal
will FF-A (e.g., support for FF-A in KVM itself), so it might be good
to have it in a common header.  I was wondering if it might even be a
good idea to reuse the Hafnium headers here (assuming I understand
licensing right):
https://review.trustedfirmware.org/plugins/gitiles/hafnium/hafnium/+/refs/heads/master/inc/vmapi/hf/ffa.h


> +
> +static ffa_fn *invoke_ffa_fn;
> +
> +static const int ffa_linux_errmap[] = {
> +       /* better than switch case as long as return value is continuous */
> +       0,              /* FFA_RET_SUCCESS */
> +       -EOPNOTSUPP,    /* FFA_RET_NOT_SUPPORTED */
> +       -EINVAL,        /* FFA_RET_INVALID_PARAMETERS */
> +       -ENOMEM,        /* FFA_RET_NO_MEMORY */
> +       -EBUSY,         /* FFA_RET_BUSY */
> +       -EINTR,         /* FFA_RET_INTERRUPTED */
> +       -EACCES,        /* FFA_RET_DENIED */
> +       -EAGAIN,        /* FFA_RET_RETRY */
> +       -ECANCELED,     /* FFA_RET_ABORTED */
> +};
> +
> +static inline int ffa_to_linux_errno(int errno)
> +{
> +       if (errno < FFA_RET_SUCCESS && errno >= FFA_RET_ABORTED)
> +               return ffa_linux_errmap[-errno];
> +       return -EINVAL;
> +}

Hardcoding the range check to be bound by FFA_RET_ABORTED could cause
some issues in the future if more error codes are added.  It might be
safer to check against the number of elements in ffa_linux_errmap.

> +
> +struct ffa_drv_info {
> +       u32 version;
> +       u16 vm_id;
> +       struct mutex rx_lock; /* lock to protect Rx buffer */
> +       struct mutex tx_lock; /* lock to protect Tx buffer */
> +       void *rx_buffer;
> +       void *tx_buffer;
> +};
> +
> +static struct ffa_drv_info *drv_info;
> +
> +static int ffa_version_check(u32 *version)
> +{
> +       ffa_res_t ver;
> +
> +       ver = invoke_ffa_fn(FFA_VERSION, FFA_DRIVER_VERSION, 0, 0, 0, 0, 0, 0);
> +
> +       if (ver.a0 == FFA_RET_NOT_SUPPORTED) {
> +               pr_info("FFA_VERSION returned not supported\n");
> +               return -EOPNOTSUPP;
> +       }
> +
> +       if (ver.a0 < FFA_MIN_VERSION || ver.a0 > FFA_DRIVER_VERSION) {
> +               pr_err("Incompatible version %d.%d found\n",
> +                      MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0));
> +               return -EINVAL;
> +       }
> +
> +       *version = ver.a0;
> +       pr_info("Version %d.%d found\n", MAJOR_VERSION(ver.a0),
> +               MINOR_VERSION(ver.a0));
> +       return 0;
> +}
> +
> +static int ffa_rxtx_map(phys_addr_t tx_buf, phys_addr_t rx_buf, u32 pg_cnt)
> +{
> +       ffa_res_t ret;
> +
> +       ret = invoke_ffa_fn(FFA_RXTX_MAP, tx_buf, rx_buf, pg_cnt, 0, 0, 0, 0);
> +
> +       if (ret.a0 == FFA_ERROR)
> +               return ffa_to_linux_errno((int)ret.a2);
> +
> +       return 0;
> +}
> +
> +static int ffa_rxtx_unmap(u16 vm_id)
> +{
> +       ffa_res_t ret;
> +
> +       ret = invoke_ffa_fn(FFA_RXTX_UNMAP, vm_id, 0, 0, 0, 0, 0, 0);
> +
> +       if (ret.a0 == FFA_ERROR)
> +               return ffa_to_linux_errno((int)ret.a2);
> +
> +       return 0;
> +}
> +
> +#define VM_ID_MASK     GENMASK(15, 0)
> +static int ffa_id_get(u16 *vm_id)
> +{
> +       ffa_res_t id;
> +
> +       id = invoke_ffa_fn(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0);
> +
> +       if (id.a0 == FFA_ERROR)
> +               return ffa_to_linux_errno((int)id.a2);
> +
> +       *vm_id = FIELD_GET(VM_ID_MASK, (id.a2));
> +
> +       return 0;
> +}
> +
> +static int __init ffa_init(void)
> +{
> +       int ret;
> +
> +       ret = ffa_transport_init(&invoke_ffa_fn);
> +       if (ret)
> +               return ret;
> +
> +       drv_info = kzalloc(sizeof(*drv_info), GFP_KERNEL);
> +       if (!drv_info)
> +               return -ENOMEM;
> +
> +       ret = ffa_version_check(&drv_info->version);
> +       if (ret)
> +               goto free_drv_info;
> +
> +       if (ffa_id_get(&drv_info->vm_id)) {
> +               pr_err("failed to obtain VM id for self\n");
> +               ret = -ENODEV;
> +               goto free_drv_info;
> +       }
> +
> +       drv_info->rx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL);
> +       if (!drv_info->rx_buffer) {
> +               ret = -ENOMEM;
> +               goto free_pages;
> +       }
> +
> +       drv_info->tx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL);
> +       if (!drv_info->tx_buffer) {
> +               ret = -ENOMEM;
> +               goto free_pages;
> +       }
> +
> +       ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer),
> +                          virt_to_phys(drv_info->rx_buffer),
> +                          RXTX_BUFFER_SIZE / FFA_PAGE_SIZE);
> +       if (ret) {
> +               pr_err("failed to register FFA RxTx buffers\n");
> +               goto free_pages;
> +       }
> +
> +       mutex_init(&drv_info->rx_lock);
> +       mutex_init(&drv_info->tx_lock);
> +
> +       return 0;
> +free_pages:
> +       if (drv_info->tx_buffer)
> +               free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
> +       free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE);
> +free_drv_info:
> +       kfree(drv_info);
> +       return ret;
> +}
> +module_init(ffa_init);
> +
> +static void __exit ffa_exit(void)
> +{
> +       ffa_rxtx_unmap(drv_info->vm_id);
> +       free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
> +       free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE);
> +       kfree(drv_info);
> +}
> +module_exit(ffa_exit);
> +
> +MODULE_ALIAS("arm-ffa");
> +MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
> +MODULE_DESCRIPTION("Arm FF-A interface driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.17.1
>

Cheers,
/fuad

WARNING: multiple messages have this Message-ID (diff)
From: Fuad Tabba <tabba@google.com>
To: Sudeep Holla <sudeep.holla@arm.com>
Cc: devicetree@vger.kernel.org, kernel-team@android.com,
	pratikp@quicinc.com, tsoni@quicinc.com,
	Will Deacon <will@kernel.org>,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 6/9] firmware: arm_ffa: Add initial Arm FFA driver support
Date: Mon, 7 Sep 2020 08:55:13 +0100	[thread overview]
Message-ID: <CA+EHjTwYm--tOGjFq0aqP_bsBPu+f1hGTYrVxsuqLw-4K+QJMA@mail.gmail.com> (raw)
In-Reply-To: <20200829170923.29949-7-sudeep.holla@arm.com>

Hi Sudeep,

I understand that this is an RFC, but I have a few suggestions about
how the FF-A interface code might be structured.  See below.

On Sat, Aug 29, 2020 at 6:09 PM Sudeep Holla <sudeep.holla@arm.com> wrote:
>
> This just add a basic driver that sets up the transport(e.g. SMCCC),
> checks the FFA version implemented, get the partition ID for self and
> sets up the Tx/Rx buffers for communication.
>
> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
> ---
>  drivers/firmware/arm_ffa/Makefile |   3 +-
>  drivers/firmware/arm_ffa/common.h |  23 +++
>  drivers/firmware/arm_ffa/driver.c | 288 ++++++++++++++++++++++++++++++
>  3 files changed, 313 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/firmware/arm_ffa/common.h
>  create mode 100644 drivers/firmware/arm_ffa/driver.c
>
> diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile
> index fadb325ee888..1a9bd2bf8752 100644
> --- a/drivers/firmware/arm_ffa/Makefile
> +++ b/drivers/firmware/arm_ffa/Makefile
> @@ -1,3 +1,4 @@
>  # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-bus.o
> +obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-bus.o ffa-driver.o
>  ffa-bus-y = bus.o
> +ffa-driver-y = driver.o
> diff --git a/drivers/firmware/arm_ffa/common.h b/drivers/firmware/arm_ffa/common.h
> new file mode 100644
> index 000000000000..720c8425dfd6
> --- /dev/null
> +++ b/drivers/firmware/arm_ffa/common.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020 ARM Ltd.
> + */
> +
> +#ifndef _FFA_COMMON_H
> +#define _FFA_COMMON_H
> +
> +#include <linux/arm-smccc.h>
> +#include <linux/err.h>
> +
> +typedef struct arm_smccc_v1_2_res ffa_res_t;
> +
> +typedef ffa_res_t
> +(ffa_fn)(unsigned long, unsigned long, unsigned long, unsigned long,
> +        unsigned long, unsigned long, unsigned long, unsigned long);
> +
> +static inline int __init ffa_transport_init(ffa_fn **invoke_ffa_fn)
> +{
> +       return -EOPNOTSUPP;
> +}
> +
> +#endif /* _FFA_COMMON_H */
> diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
> new file mode 100644
> index 000000000000..3670ba400f89
> --- /dev/null
> +++ b/drivers/firmware/arm_ffa/driver.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Arm Firmware Framework for ARMv8-A(FFA) interface driver
> + *
> + * The Arm FFA specification[1] describes a software architecture to
> + * leverages the virtualization extension to isolate software images
> + * provided by an ecosystem of vendors from each other and describes
> + * interfaces that standardize communication between the various software
> + * images including communication between images in the Secure world and
> + * Normal world. Any Hypervisor could use the FFA interfaces to enable
> + * communication between VMs it manages.
> + *
> + * The Hypervisor a.k.a Partition managers in FFA terminology can assign
> + * system resources(Memory regions, Devices, CPU cycles) to the partitions
> + * and manage isolation amongst them.
> + *
> + * [1] https://developer.arm.com/docs/den0077/latest
> + *
> + * Copyright (C) 2020 Arm Ltd.
> + */
> +
> +#define DRIVER_NAME "ARM FF-A"
> +#define pr_fmt(fmt) DRIVER_NAME ": " fmt
> +
> +#include <linux/bitfield.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/arm_ffa.h>
> +
> +#include "common.h"
> +
> +#define FFA_SMC(calling_convention, func_num)                          \
> +       ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention),   \
> +                          ARM_SMCCC_OWNER_STANDARD, (func_num))
> +
> +#define FFA_SMC_32(func_num)   FFA_SMC(ARM_SMCCC_SMC_32, (func_num))
> +#define FFA_SMC_64(func_num)   FFA_SMC(ARM_SMCCC_SMC_64, (func_num))
> +
> +#define FFA_ERROR                      FFA_SMC_32(0x60)
> +#define FFA_SUCCESS                    FFA_SMC_32(0x61)
> +#define FFA_INTERRUPT                  FFA_SMC_32(0x62)
> +#define FFA_VERSION                    FFA_SMC_32(0x63)
> +#define FFA_FEATURES                   FFA_SMC_32(0x64)
> +#define FFA_RX_RELEASE                 FFA_SMC_32(0x65)
> +#define FFA_RXTX_MAP                   FFA_SMC_32(0x66)
> +#define FFA_RXTX_UNMAP                 FFA_SMC_32(0x67)
> +#define FFA_PARTITION_INFO_GET         FFA_SMC_32(0x68)
> +#define FFA_ID_GET                     FFA_SMC_32(0x69)
> +#define FFA_MSG_POLL                   FFA_SMC_32(0x6A)
> +#define FFA_MSG_WAIT                   FFA_SMC_32(0x6B)
> +#define FFA_YIELD                      FFA_SMC_32(0x6C)
> +#define FFA_RUN                                FFA_SMC_32(0x6D)
> +#define FFA_MSG_SEND                   FFA_SMC_32(0x6E)
> +#define FFA_MSG_SEND_DIRECT_REQ                FFA_SMC_32(0x6F)
> +#define FFA_FN64_MSG_SEND_DIRECT_REQ   FFA_SMC_64(0x6F)
> +#define FFA_MSG_SEND_DIRECT_RESP       FFA_SMC_32(0x70)
> +#define FFA_FN64_MSG_SEND_DIRECT_RESP  FFA_SMC_64(0x70)
> +#define FFA_MEM_DONATE                 FFA_SMC_32(0x71)
> +#define FFA_FN64_MEM_DONATE            FFA_SMC_32(0x71)
> +#define FFA_MEM_LEND                   FFA_SMC_32(0x72)
> +#define FFA_FN64_MEM_LEND              FFA_SMC_32(0x72)
> +#define FFA_MEM_SHARE                  FFA_SMC_32(0x73)
> +#define FFA_FN64_MEM_SHARE             FFA_SMC_64(0x73)
> +#define FFA_MEM_RETRIEVE_REQ           FFA_SMC_32(0x74)
> +#define FFA_FN64_MEM_RETRIEVE_REQ      FFA_SMC_64(0x74)
> +#define FFA_MEM_RETRIEVE_RESP          FFA_SMC_32(0x75)
> +#define FFA_MEM_RELINQUISH             FFA_SMC_32(0x76)
> +#define FFA_MEM_RECLAIM                        FFA_SMC_32(0x77)
> +#define FFA_MEM_OP_PAUSE               FFA_SMC_32(0x78)
> +#define FFA_MEM_OP_RESUME              FFA_SMC_32(0x79)
> +#define FFA_MEM_FRAG_RX                        FFA_SMC_32(0x7A)
> +#define FFA_MEM_FRAG_TX                        FFA_SMC_32(0x7B)
> +#define FFA_NORMAL_WORLD_RESUME                FFA_SMC_32(0x7C)
> +
> +/*
> + * For some calls it is necessary to use SMC64 to pass or return 64-bit values.
> + * For such calls FFA_FN_NATIVE(name) will choose the appropriate
> + * (native-width) function ID.
> + */
> +#ifdef CONFIG_64BIT
> +#define FFA_FN_NATIVE(name)    FFA_FN64_##name
> +#else
> +#define FFA_FN_NATIVE(name)    FFA_##name
> +#endif
> +
> +/* FFA error codes. */
> +#define FFA_RET_SUCCESS            (0)
> +#define FFA_RET_NOT_SUPPORTED      (-1)
> +#define FFA_RET_INVALID_PARAMETERS (-2)
> +#define FFA_RET_NO_MEMORY          (-3)
> +#define FFA_RET_BUSY               (-4)
> +#define FFA_RET_INTERRUPTED        (-5)
> +#define FFA_RET_DENIED             (-6)
> +#define FFA_RET_RETRY              (-7)
> +#define FFA_RET_ABORTED            (-8)
> +
> +#define MAJOR_VERSION_MASK     GENMASK(30, 16)
> +#define MINOR_VERSION_MASK     GENMASK(15, 0)
> +#define MAJOR_VERSION(x)       (u16)(FIELD_GET(MAJOR_VERSION_MASK, (x)))
> +#define MINOR_VERSION(x)       (u16)(FIELD_GET(MINOR_VERSION_MASK, (x)))
> +#define PACK_VERSION_INFO(major, minor)                        \
> +       (FIELD_PREP(MAJOR_VERSION_MASK, (major)) |      \
> +        FIELD_PREP(MINOR_VERSION_MASK, (minor)))
> +#define FFA_VERSION_1_0        PACK_VERSION_INFO(1, 0)
> +#define FFA_MIN_VERSION        FFA_VERSION_1_0
> +#define FFA_DRIVER_VERSION     FFA_VERSION_1_0
> +
> +#define SENDER_ID_MASK         GENMASK(31, 16)
> +#define RECEIVER_ID_MASK       GENMASK(15, 0)
> +#define SENDER_ID(x)           (u16)(FIELD_GET(SENDER_ID_MASK, (x)))
> +#define RECEIVER_ID(x)         (u16)(FIELD_GET(RECEIVER_ID_MASK, (x)))
> +#define PACK_TARGET_INFO(s, r)         \
> +       (FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r)))
> +
> +/**
> + * FF-A specification mentions explicitly about '4K pages'. This should
> + * not be confused with the kernel PAGE_SIZE, which is the translation
> + * granule kernel is configured and may be one among 4K, 16K and 64K.
> + */
> +#define FFA_PAGE_SIZE          SZ_4K
> +/* Keeping RX TX buffer size as 64K for now */
> +#define RXTX_BUFFER_SIZE       SZ_64K

The code/definitions above will be reused in other parts that deal
will FF-A (e.g., support for FF-A in KVM itself), so it might be good
to have it in a common header.  I was wondering if it might even be a
good idea to reuse the Hafnium headers here (assuming I understand
licensing right):
https://review.trustedfirmware.org/plugins/gitiles/hafnium/hafnium/+/refs/heads/master/inc/vmapi/hf/ffa.h


> +
> +static ffa_fn *invoke_ffa_fn;
> +
> +static const int ffa_linux_errmap[] = {
> +       /* better than switch case as long as return value is continuous */
> +       0,              /* FFA_RET_SUCCESS */
> +       -EOPNOTSUPP,    /* FFA_RET_NOT_SUPPORTED */
> +       -EINVAL,        /* FFA_RET_INVALID_PARAMETERS */
> +       -ENOMEM,        /* FFA_RET_NO_MEMORY */
> +       -EBUSY,         /* FFA_RET_BUSY */
> +       -EINTR,         /* FFA_RET_INTERRUPTED */
> +       -EACCES,        /* FFA_RET_DENIED */
> +       -EAGAIN,        /* FFA_RET_RETRY */
> +       -ECANCELED,     /* FFA_RET_ABORTED */
> +};
> +
> +static inline int ffa_to_linux_errno(int errno)
> +{
> +       if (errno < FFA_RET_SUCCESS && errno >= FFA_RET_ABORTED)
> +               return ffa_linux_errmap[-errno];
> +       return -EINVAL;
> +}

Hardcoding the range check to be bound by FFA_RET_ABORTED could cause
some issues in the future if more error codes are added.  It might be
safer to check against the number of elements in ffa_linux_errmap.

> +
> +struct ffa_drv_info {
> +       u32 version;
> +       u16 vm_id;
> +       struct mutex rx_lock; /* lock to protect Rx buffer */
> +       struct mutex tx_lock; /* lock to protect Tx buffer */
> +       void *rx_buffer;
> +       void *tx_buffer;
> +};
> +
> +static struct ffa_drv_info *drv_info;
> +
> +static int ffa_version_check(u32 *version)
> +{
> +       ffa_res_t ver;
> +
> +       ver = invoke_ffa_fn(FFA_VERSION, FFA_DRIVER_VERSION, 0, 0, 0, 0, 0, 0);
> +
> +       if (ver.a0 == FFA_RET_NOT_SUPPORTED) {
> +               pr_info("FFA_VERSION returned not supported\n");
> +               return -EOPNOTSUPP;
> +       }
> +
> +       if (ver.a0 < FFA_MIN_VERSION || ver.a0 > FFA_DRIVER_VERSION) {
> +               pr_err("Incompatible version %d.%d found\n",
> +                      MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0));
> +               return -EINVAL;
> +       }
> +
> +       *version = ver.a0;
> +       pr_info("Version %d.%d found\n", MAJOR_VERSION(ver.a0),
> +               MINOR_VERSION(ver.a0));
> +       return 0;
> +}
> +
> +static int ffa_rxtx_map(phys_addr_t tx_buf, phys_addr_t rx_buf, u32 pg_cnt)
> +{
> +       ffa_res_t ret;
> +
> +       ret = invoke_ffa_fn(FFA_RXTX_MAP, tx_buf, rx_buf, pg_cnt, 0, 0, 0, 0);
> +
> +       if (ret.a0 == FFA_ERROR)
> +               return ffa_to_linux_errno((int)ret.a2);
> +
> +       return 0;
> +}
> +
> +static int ffa_rxtx_unmap(u16 vm_id)
> +{
> +       ffa_res_t ret;
> +
> +       ret = invoke_ffa_fn(FFA_RXTX_UNMAP, vm_id, 0, 0, 0, 0, 0, 0);
> +
> +       if (ret.a0 == FFA_ERROR)
> +               return ffa_to_linux_errno((int)ret.a2);
> +
> +       return 0;
> +}
> +
> +#define VM_ID_MASK     GENMASK(15, 0)
> +static int ffa_id_get(u16 *vm_id)
> +{
> +       ffa_res_t id;
> +
> +       id = invoke_ffa_fn(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0);
> +
> +       if (id.a0 == FFA_ERROR)
> +               return ffa_to_linux_errno((int)id.a2);
> +
> +       *vm_id = FIELD_GET(VM_ID_MASK, (id.a2));
> +
> +       return 0;
> +}
> +
> +static int __init ffa_init(void)
> +{
> +       int ret;
> +
> +       ret = ffa_transport_init(&invoke_ffa_fn);
> +       if (ret)
> +               return ret;
> +
> +       drv_info = kzalloc(sizeof(*drv_info), GFP_KERNEL);
> +       if (!drv_info)
> +               return -ENOMEM;
> +
> +       ret = ffa_version_check(&drv_info->version);
> +       if (ret)
> +               goto free_drv_info;
> +
> +       if (ffa_id_get(&drv_info->vm_id)) {
> +               pr_err("failed to obtain VM id for self\n");
> +               ret = -ENODEV;
> +               goto free_drv_info;
> +       }
> +
> +       drv_info->rx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL);
> +       if (!drv_info->rx_buffer) {
> +               ret = -ENOMEM;
> +               goto free_pages;
> +       }
> +
> +       drv_info->tx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL);
> +       if (!drv_info->tx_buffer) {
> +               ret = -ENOMEM;
> +               goto free_pages;
> +       }
> +
> +       ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer),
> +                          virt_to_phys(drv_info->rx_buffer),
> +                          RXTX_BUFFER_SIZE / FFA_PAGE_SIZE);
> +       if (ret) {
> +               pr_err("failed to register FFA RxTx buffers\n");
> +               goto free_pages;
> +       }
> +
> +       mutex_init(&drv_info->rx_lock);
> +       mutex_init(&drv_info->tx_lock);
> +
> +       return 0;
> +free_pages:
> +       if (drv_info->tx_buffer)
> +               free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
> +       free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE);
> +free_drv_info:
> +       kfree(drv_info);
> +       return ret;
> +}
> +module_init(ffa_init);
> +
> +static void __exit ffa_exit(void)
> +{
> +       ffa_rxtx_unmap(drv_info->vm_id);
> +       free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
> +       free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE);
> +       kfree(drv_info);
> +}
> +module_exit(ffa_exit);
> +
> +MODULE_ALIAS("arm-ffa");
> +MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
> +MODULE_DESCRIPTION("Arm FF-A interface driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.17.1
>

Cheers,
/fuad

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2020-09-07  7:55 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-29 17:09 [PATCH 0/9] firmware: Add initial support for Arm FF-A Sudeep Holla
2020-08-29 17:09 ` Sudeep Holla
2020-08-29 17:09 ` [PATCH 1/9] dt-bindings: Arm: Add Firmware Framework for Armv8-A (FF-A) binding Sudeep Holla
2020-08-29 17:09   ` Sudeep Holla
2020-09-01 16:03   ` Jonathan Cameron
2020-09-01 16:03     ` Jonathan Cameron
2020-09-07 11:40     ` Sudeep Holla
2020-09-07 11:40       ` Sudeep Holla
2020-09-02 22:14   ` Rob Herring
2020-09-02 22:14     ` Rob Herring
2020-11-03 15:59     ` Sudeep Holla
2020-11-03 15:59       ` Sudeep Holla
2020-08-29 17:09 ` [PATCH 2/9] dt-bindings: Arm: Extend FF-A binding to support in-kernel usage of partitions Sudeep Holla
2020-08-29 17:09   ` Sudeep Holla
2020-09-02 21:36   ` Rob Herring
2020-09-02 21:36     ` Rob Herring
2020-09-07 11:41     ` Sudeep Holla
2020-09-07 11:41       ` Sudeep Holla
2020-08-29 17:09 ` [PATCH 3/9] arm64: smccc: Add support for SMCCCv1.2 input/output registers Sudeep Holla
2020-08-29 17:09   ` Sudeep Holla
2020-08-29 17:09 ` [PATCH 4/9] firmware: smccc: export both smccc functions Sudeep Holla
2020-08-29 17:09   ` Sudeep Holla
2020-08-29 17:09 ` [PATCH 5/9] firmware: arm_ffa: Add initial FFA bus support for device enumeration Sudeep Holla
2020-08-29 17:09   ` Sudeep Holla
2020-08-29 17:09 ` [PATCH 6/9] firmware: arm_ffa: Add initial Arm FFA driver support Sudeep Holla
2020-08-29 17:09   ` Sudeep Holla
2020-09-07  7:55   ` Fuad Tabba [this message]
2020-09-07  7:55     ` Fuad Tabba
2020-09-07  9:29     ` Sudeep Holla
2020-09-07  9:29       ` Sudeep Holla
2020-08-29 17:09 ` [PATCH 7/9] firmware: arm_ffa: Add support for SMCCC as transport to FFA driver Sudeep Holla
2020-08-29 17:09   ` Sudeep Holla
2020-09-01 16:23   ` Jonathan Cameron
2020-09-01 16:23     ` Jonathan Cameron
2020-08-29 17:09 ` [PATCH 8/9] firmware: arm_ffa: Setup and register all the KVM managed partitions Sudeep Holla
2020-08-29 17:09   ` Sudeep Holla
2020-09-01 16:34   ` Jonathan Cameron
2020-09-01 16:34     ` Jonathan Cameron
2020-09-07 11:20   ` Achin Gupta
2020-09-07 11:20     ` Achin Gupta
2020-08-29 17:09 ` [PATCH 9/9] firmware: arm_ffa: Setup in-kernel users of FFA partitions Sudeep Holla
2020-08-29 17:09   ` Sudeep Holla
2020-09-01 16:38   ` Jonathan Cameron
2020-09-01 16:38     ` Jonathan Cameron
2020-09-07 11:32   ` Achin Gupta
2020-09-07 11:32     ` Achin Gupta
2020-09-07 12:04     ` Andrew Walbran
2020-09-07 12:04       ` Andrew Walbran

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CA+EHjTwYm--tOGjFq0aqP_bsBPu+f1hGTYrVxsuqLw-4K+QJMA@mail.gmail.com \
    --to=tabba@google.com \
    --cc=devicetree@vger.kernel.org \
    --cc=kernel-team@android.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=pratikp@quicinc.com \
    --cc=sudeep.holla@arm.com \
    --cc=tsoni@quicinc.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.