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
next prev parent 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: linkBe 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.