Parse the FFA nodes from the device-tree and register all the partitions managed by the KVM hypervisor. All the partitions including the host(self) are registered as the character device with a set of file operations. Most of the interface will concentrated in the ioctl. For now, we have a tiny set of initial ioctls implemented. Signed-off-by: Sudeep Holla <sudeep.holla@xxxxxxx> --- drivers/firmware/arm_ffa/Makefile | 2 +- drivers/firmware/arm_ffa/common.h | 5 + drivers/firmware/arm_ffa/driver.c | 27 +++++ drivers/firmware/arm_ffa/hyp_partitions.c | 132 ++++++++++++++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_ffa/hyp_partitions.c diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile index 9d9f37523200..eac280c27cac 100644 --- a/drivers/firmware/arm_ffa/Makefile +++ b/drivers/firmware/arm_ffa/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only ffa-bus-y = bus.o -ffa-driver-y = driver.o +ffa-driver-y = driver.o hyp_partitions.o ffa-transport-$(CONFIG_ARM_FFA_SMCCC) += smccc.o ffa-module-objs := $(ffa-bus-y) $(ffa-driver-y) $(ffa-transport-y) obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-module.o diff --git a/drivers/firmware/arm_ffa/common.h b/drivers/firmware/arm_ffa/common.h index d019348bf67d..12bb960deb09 100644 --- a/drivers/firmware/arm_ffa/common.h +++ b/drivers/firmware/arm_ffa/common.h @@ -8,6 +8,7 @@ #include <linux/arm-smccc.h> #include <linux/err.h> +#include <linux/fs.h> typedef struct arm_smccc_v1_2_res ffa_res_t; @@ -15,8 +16,12 @@ typedef ffa_res_t (ffa_fn)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); +int __init ffa_hyp_partitions_init(void); int __init arm_ffa_bus_init(void); void __exit arm_ffa_bus_exit(void); +struct ffa_device *ffa_device_get_from_minor(int minor); +int ffa_setup_partitions(const char *compatible, + const struct file_operations *fops); #ifdef CONFIG_ARM_FFA_SMCCC int __init ffa_transport_init(ffa_fn **invoke_ffa_fn); diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 2e5fa56fffb7..0aa3e4d02896 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -241,6 +241,31 @@ static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, return 0; } +struct ffa_device *ffa_device_get_from_minor(int minor) +{ + struct list_head *p; + struct ffa_device *ffa_dev = NULL; + + mutex_lock(&ffa_devs_list_mutex); + + list_for_each(p, &ffa_devs_list) { + struct device *dev; + struct ffa_device *tmp_dev; + + tmp_dev = list_to_ffa_dev(p); + dev = &tmp_dev->dev; + + if (minor == MINOR(dev->devt)) { + ffa_dev = tmp_dev; + break; + } + } + + mutex_unlock(&ffa_devs_list_mutex); + + return ffa_dev; +} + static void ffa_device_get(struct ffa_device *ffa_dev) { mutex_lock(&ffa_dev->mutex); @@ -466,6 +491,8 @@ static int __init ffa_init(void) /* Set up all the partitions which have in-kernel drivers */ ffa_setup_partitions("arm,ffa-1.0", NULL); + ffa_hyp_partitions_init(); + return 0; free_pages: if (drv_info->tx_buffer) diff --git a/drivers/firmware/arm_ffa/hyp_partitions.c b/drivers/firmware/arm_ffa/hyp_partitions.c new file mode 100644 index 000000000000..985f66d4322b --- /dev/null +++ b/drivers/firmware/arm_ffa/hyp_partitions.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Arm Firmware Framework for ARMv8-A(FFA) userspace interface + * + * Copyright (C) 2020 Arm Ltd. + */ + +#define pr_fmt(fmt) "ARM FF-A USER : " fmt + +#include <linux/arm_ffa.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/uuid.h> +#include <uapi/linux/arm_ffa.h> + +#include "common.h" + +struct ffa_dev_data { + struct ffa_device *dev; + const struct ffa_dev_ops *ops; +}; + +static int ffa_open(struct inode *inode, struct file *filp) +{ + struct ffa_dev_data *ffa_data; + + ffa_data = kzalloc(sizeof(*ffa_data), GFP_KERNEL); + if (!ffa_data) + return -ENOMEM; + + ffa_data->dev = ffa_device_get_from_minor(iminor(inode)); + if (!ffa_data->dev) { + kfree(ffa_data); + return -EINVAL; + } + + ffa_data->ops = ffa_dev_ops_get(ffa_data->dev); + if (!ffa_data->ops) { + kfree(ffa_data); + return -EINVAL; + } + + ffa_data->ops->open(ffa_data->dev); + + filp->private_data = ffa_data; + + return 0; +} + +static int ffa_release(struct inode *inode, struct file *filp) +{ + struct ffa_dev_data *ffa_data = filp->private_data; + + ffa_data->ops->close(ffa_data->dev); + + filp->private_data = NULL; + kfree(ffa_data); + + return 0; +} + +static long ffa_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) +{ + long r = -EINVAL; + void __user *argp = (void __user *)arg; + struct ffa_dev_data *ffa_data = filp->private_data; + struct ffa_device *ffa_dev = ffa_data->dev; + + switch (ioctl) { + case FFA_GET_API_VERSION: + case FFA_GET_PARTITION_ID: + if (arg) + return r; + return ffa_data->ops->ioctl(ffa_dev, ioctl, NULL); + case FFA_GET_PARTITION_INFO: { + struct ffa_part_info __user *pinfo = argp; + struct ffa_part_info info; + unsigned int count; + + r = -EFAULT; + if (copy_from_user(&info, pinfo, sizeof(info))) + break; + count = ffa_data->ops->ioctl(ffa_dev, ioctl, &info); + if (count > 1) { + r = -E2BIG; + break; + } + r = -EFAULT; + if (copy_to_user(pinfo, &info, sizeof(info))) + break; + r = 0; + break; + } + case FFA_SEND_RECEIVE_SYNC: { + struct ffa_send_recv_sync __user *udata = argp; + struct ffa_send_recv_sync kdata; + + r = -EFAULT; + if (copy_from_user(&kdata, udata, sizeof(kdata))) + break; + r = ffa_data->ops->ioctl(ffa_dev, ioctl, &kdata); + if (r) + break; + if (copy_to_user(udata, &kdata, sizeof(kdata))) + break; + break; + } + default: + r = -EINVAL; + } + return r; +} + +static const struct file_operations ffa_fops = { + .owner = THIS_MODULE, + .open = ffa_open, + .release = ffa_release, + .unlocked_ioctl = ffa_ioctl, + .llseek = noop_llseek, +}; + +int __init ffa_hyp_partitions_init(void) +{ + /* Set up all the partitions that KVM hypervisor maintains */ + ffa_setup_partitions("arm,ffa-1.0-hypervisor", &ffa_fops); + + return 0; +} -- 2.25.1