256 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2021 ARM Ltd.4 */5 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt7 8#include <linux/arm_ffa.h>9#include <linux/device.h>10#include <linux/fs.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/slab.h>14#include <linux/types.h>15 16#include "common.h"17 18#define SCMI_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb"19 20static DEFINE_IDA(ffa_bus_id);21 22static int ffa_device_match(struct device *dev, const struct device_driver *drv)23{24 const struct ffa_device_id *id_table;25 struct ffa_device *ffa_dev;26 27 id_table = to_ffa_driver(drv)->id_table;28 ffa_dev = to_ffa_dev(dev);29 30 while (!uuid_is_null(&id_table->uuid)) {31 /*32 * FF-A v1.0 doesn't provide discovery of UUIDs, just the33 * partition IDs, so match it unconditionally here and handle34 * it via the installed bus notifier during driver binding.35 */36 if (uuid_is_null(&ffa_dev->uuid))37 return 1;38 39 if (uuid_equal(&ffa_dev->uuid, &id_table->uuid))40 return 1;41 id_table++;42 }43 44 return 0;45}46 47static int ffa_device_probe(struct device *dev)48{49 struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);50 struct ffa_device *ffa_dev = to_ffa_dev(dev);51 52 /* UUID can be still NULL with FF-A v1.0, so just skip probing them */53 if (uuid_is_null(&ffa_dev->uuid))54 return -ENODEV;55 56 return ffa_drv->probe(ffa_dev);57}58 59static void ffa_device_remove(struct device *dev)60{61 struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);62 63 if (ffa_drv->remove)64 ffa_drv->remove(to_ffa_dev(dev));65}66 67static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *env)68{69 const struct ffa_device *ffa_dev = to_ffa_dev(dev);70 71 return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT,72 ffa_dev->vm_id, &ffa_dev->uuid);73}74 75static ssize_t modalias_show(struct device *dev,76 struct device_attribute *attr, char *buf)77{78 struct ffa_device *ffa_dev = to_ffa_dev(dev);79 80 return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id,81 &ffa_dev->uuid);82}83static DEVICE_ATTR_RO(modalias);84 85static ssize_t partition_id_show(struct device *dev,86 struct device_attribute *attr, char *buf)87{88 struct ffa_device *ffa_dev = to_ffa_dev(dev);89 90 return sprintf(buf, "0x%04x\n", ffa_dev->vm_id);91}92static DEVICE_ATTR_RO(partition_id);93 94static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,95 char *buf)96{97 struct ffa_device *ffa_dev = to_ffa_dev(dev);98 99 return sprintf(buf, "%pUb\n", &ffa_dev->uuid);100}101static DEVICE_ATTR_RO(uuid);102 103static struct attribute *ffa_device_attributes_attrs[] = {104 &dev_attr_partition_id.attr,105 &dev_attr_uuid.attr,106 &dev_attr_modalias.attr,107 NULL,108};109ATTRIBUTE_GROUPS(ffa_device_attributes);110 111const struct bus_type ffa_bus_type = {112 .name = "arm_ffa",113 .match = ffa_device_match,114 .probe = ffa_device_probe,115 .remove = ffa_device_remove,116 .uevent = ffa_device_uevent,117 .dev_groups = ffa_device_attributes_groups,118};119EXPORT_SYMBOL_GPL(ffa_bus_type);120 121int ffa_driver_register(struct ffa_driver *driver, struct module *owner,122 const char *mod_name)123{124 int ret;125 126 if (!driver->probe)127 return -EINVAL;128 129 driver->driver.bus = &ffa_bus_type;130 driver->driver.name = driver->name;131 driver->driver.owner = owner;132 driver->driver.mod_name = mod_name;133 134 ret = driver_register(&driver->driver);135 if (!ret)136 pr_debug("registered new ffa driver %s\n", driver->name);137 138 return ret;139}140EXPORT_SYMBOL_GPL(ffa_driver_register);141 142void ffa_driver_unregister(struct ffa_driver *driver)143{144 driver_unregister(&driver->driver);145}146EXPORT_SYMBOL_GPL(ffa_driver_unregister);147 148static void ffa_release_device(struct device *dev)149{150 struct ffa_device *ffa_dev = to_ffa_dev(dev);151 152 ida_free(&ffa_bus_id, ffa_dev->id);153 kfree(ffa_dev);154}155 156static int __ffa_devices_unregister(struct device *dev, void *data)157{158 device_unregister(dev);159 160 return 0;161}162 163static void ffa_devices_unregister(void)164{165 bus_for_each_dev(&ffa_bus_type, NULL, NULL,166 __ffa_devices_unregister);167}168 169bool ffa_device_is_valid(struct ffa_device *ffa_dev)170{171 bool valid = false;172 struct device *dev = NULL;173 struct ffa_device *tmp_dev;174 175 do {176 dev = bus_find_next_device(&ffa_bus_type, dev);177 tmp_dev = to_ffa_dev(dev);178 if (tmp_dev == ffa_dev) {179 valid = true;180 break;181 }182 put_device(dev);183 } while (dev);184 185 put_device(dev);186 187 return valid;188}189 190struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id,191 const struct ffa_ops *ops)192{193 int id, ret;194 struct device *dev;195 struct ffa_device *ffa_dev;196 197 id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL);198 if (id < 0)199 return NULL;200 201 ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL);202 if (!ffa_dev) {203 ida_free(&ffa_bus_id, id);204 return NULL;205 }206 207 dev = &ffa_dev->dev;208 dev->bus = &ffa_bus_type;209 dev->release = ffa_release_device;210 dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);211 212 ffa_dev->id = id;213 ffa_dev->vm_id = vm_id;214 ffa_dev->ops = ops;215 uuid_copy(&ffa_dev->uuid, uuid);216 217 ret = device_register(&ffa_dev->dev);218 if (ret) {219 dev_err(dev, "unable to register device %s err=%d\n",220 dev_name(dev), ret);221 put_device(dev);222 return NULL;223 }224 225 return ffa_dev;226}227EXPORT_SYMBOL_GPL(ffa_device_register);228 229void ffa_device_unregister(struct ffa_device *ffa_dev)230{231 if (!ffa_dev)232 return;233 234 device_unregister(&ffa_dev->dev);235}236EXPORT_SYMBOL_GPL(ffa_device_unregister);237 238static int __init arm_ffa_bus_init(void)239{240 return bus_register(&ffa_bus_type);241}242subsys_initcall(arm_ffa_bus_init);243 244static void __exit arm_ffa_bus_exit(void)245{246 ffa_devices_unregister();247 bus_unregister(&ffa_bus_type);248 ida_destroy(&ffa_bus_id);249}250module_exit(arm_ffa_bus_exit);251 252MODULE_ALIAS("ffa-core");253MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");254MODULE_DESCRIPTION("ARM FF-A bus");255MODULE_LICENSE("GPL");256