1e7818584SSudeep Holla // SPDX-License-Identifier: GPL-2.0 2e7818584SSudeep Holla /* 3e7818584SSudeep Holla * Copyright (C) 2021 ARM Ltd. 4e7818584SSudeep Holla */ 5e7818584SSudeep Holla 6e7818584SSudeep Holla #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7e7818584SSudeep Holla 8e7818584SSudeep Holla #include <linux/arm_ffa.h> 9e7818584SSudeep Holla #include <linux/device.h> 10e7818584SSudeep Holla #include <linux/fs.h> 11e7818584SSudeep Holla #include <linux/kernel.h> 12e7818584SSudeep Holla #include <linux/module.h> 13e7818584SSudeep Holla #include <linux/slab.h> 14e7818584SSudeep Holla #include <linux/types.h> 15e7818584SSudeep Holla 163bbfe987SSudeep Holla #include "common.h" 173bbfe987SSudeep Holla 1822779149SSudeep Holla #define SCMI_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb" 1922779149SSudeep Holla 2019b87664SSudeep Holla static DEFINE_IDA(ffa_bus_id); 2119b87664SSudeep Holla 22e7818584SSudeep Holla static int ffa_device_match(struct device *dev, struct device_driver *drv) 23e7818584SSudeep Holla { 24e7818584SSudeep Holla const struct ffa_device_id *id_table; 25e7818584SSudeep Holla struct ffa_device *ffa_dev; 26e7818584SSudeep Holla 27e7818584SSudeep Holla id_table = to_ffa_driver(drv)->id_table; 28e7818584SSudeep Holla ffa_dev = to_ffa_dev(dev); 29e7818584SSudeep Holla 30e7818584SSudeep Holla while (!uuid_is_null(&id_table->uuid)) { 31d0c0bce8SSudeep Holla /* 32d0c0bce8SSudeep Holla * FF-A v1.0 doesn't provide discovery of UUIDs, just the 33*9dd15934SSudeep Holla * partition IDs, so match it unconditionally here and handle 34*9dd15934SSudeep Holla * it via the installed bus notifier during driver binding. 35d0c0bce8SSudeep Holla */ 36d0c0bce8SSudeep Holla if (uuid_is_null(&ffa_dev->uuid)) 37*9dd15934SSudeep Holla return 1; 38d0c0bce8SSudeep Holla 39e7818584SSudeep Holla if (uuid_equal(&ffa_dev->uuid, &id_table->uuid)) 40e7818584SSudeep Holla return 1; 41e7818584SSudeep Holla id_table++; 42e7818584SSudeep Holla } 43e7818584SSudeep Holla 44e7818584SSudeep Holla return 0; 45e7818584SSudeep Holla } 46e7818584SSudeep Holla 47e7818584SSudeep Holla static int ffa_device_probe(struct device *dev) 48e7818584SSudeep Holla { 49e7818584SSudeep Holla struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver); 50e7818584SSudeep Holla struct ffa_device *ffa_dev = to_ffa_dev(dev); 51e7818584SSudeep Holla 52*9dd15934SSudeep Holla /* UUID can be still NULL with FF-A v1.0, so just skip probing them */ 53*9dd15934SSudeep Holla if (uuid_is_null(&ffa_dev->uuid)) 54*9dd15934SSudeep Holla return -ENODEV; 55*9dd15934SSudeep Holla 56e7818584SSudeep Holla return ffa_drv->probe(ffa_dev); 57e7818584SSudeep Holla } 58e7818584SSudeep Holla 59244f5d59SSudeep Holla static void ffa_device_remove(struct device *dev) 60244f5d59SSudeep Holla { 61244f5d59SSudeep Holla struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver); 62244f5d59SSudeep Holla 63b71b5524SSudeep Holla if (ffa_drv->remove) 64244f5d59SSudeep Holla ffa_drv->remove(to_ffa_dev(dev)); 65244f5d59SSudeep Holla } 66244f5d59SSudeep Holla 672a81ada3SGreg Kroah-Hartman static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *env) 68e7818584SSudeep Holla { 692a81ada3SGreg Kroah-Hartman const struct ffa_device *ffa_dev = to_ffa_dev(dev); 70e7818584SSudeep Holla 7122779149SSudeep Holla return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT, 72e7818584SSudeep Holla ffa_dev->vm_id, &ffa_dev->uuid); 73e7818584SSudeep Holla } 74e7818584SSudeep Holla 7522779149SSudeep Holla static ssize_t modalias_show(struct device *dev, 7622779149SSudeep Holla struct device_attribute *attr, char *buf) 7722779149SSudeep Holla { 7822779149SSudeep Holla struct ffa_device *ffa_dev = to_ffa_dev(dev); 7922779149SSudeep Holla 8022779149SSudeep Holla return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id, 8122779149SSudeep Holla &ffa_dev->uuid); 8222779149SSudeep Holla } 8322779149SSudeep Holla static DEVICE_ATTR_RO(modalias); 8422779149SSudeep Holla 85e7818584SSudeep Holla static ssize_t partition_id_show(struct device *dev, 86e7818584SSudeep Holla struct device_attribute *attr, char *buf) 87e7818584SSudeep Holla { 88e7818584SSudeep Holla struct ffa_device *ffa_dev = to_ffa_dev(dev); 89e7818584SSudeep Holla 90e7818584SSudeep Holla return sprintf(buf, "0x%04x\n", ffa_dev->vm_id); 91e7818584SSudeep Holla } 92e7818584SSudeep Holla static DEVICE_ATTR_RO(partition_id); 93e7818584SSudeep Holla 94e7818584SSudeep Holla static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, 95e7818584SSudeep Holla char *buf) 96e7818584SSudeep Holla { 97e7818584SSudeep Holla struct ffa_device *ffa_dev = to_ffa_dev(dev); 98e7818584SSudeep Holla 99e7818584SSudeep Holla return sprintf(buf, "%pUb\n", &ffa_dev->uuid); 100e7818584SSudeep Holla } 101e7818584SSudeep Holla static DEVICE_ATTR_RO(uuid); 102e7818584SSudeep Holla 103e7818584SSudeep Holla static struct attribute *ffa_device_attributes_attrs[] = { 104e7818584SSudeep Holla &dev_attr_partition_id.attr, 105e7818584SSudeep Holla &dev_attr_uuid.attr, 10622779149SSudeep Holla &dev_attr_modalias.attr, 107e7818584SSudeep Holla NULL, 108e7818584SSudeep Holla }; 109e7818584SSudeep Holla ATTRIBUTE_GROUPS(ffa_device_attributes); 110e7818584SSudeep Holla 111989e8661SRicardo B. Marliere const struct bus_type ffa_bus_type = { 112e7818584SSudeep Holla .name = "arm_ffa", 113e7818584SSudeep Holla .match = ffa_device_match, 114e7818584SSudeep Holla .probe = ffa_device_probe, 115244f5d59SSudeep Holla .remove = ffa_device_remove, 116e7818584SSudeep Holla .uevent = ffa_device_uevent, 117e7818584SSudeep Holla .dev_groups = ffa_device_attributes_groups, 118e7818584SSudeep Holla }; 119e7818584SSudeep Holla EXPORT_SYMBOL_GPL(ffa_bus_type); 120e7818584SSudeep Holla 121e7818584SSudeep Holla int ffa_driver_register(struct ffa_driver *driver, struct module *owner, 122e7818584SSudeep Holla const char *mod_name) 123e7818584SSudeep Holla { 124e7818584SSudeep Holla int ret; 125e7818584SSudeep Holla 12692743071SUwe Kleine-König if (!driver->probe) 12792743071SUwe Kleine-König return -EINVAL; 12892743071SUwe Kleine-König 129e7818584SSudeep Holla driver->driver.bus = &ffa_bus_type; 130e7818584SSudeep Holla driver->driver.name = driver->name; 131e7818584SSudeep Holla driver->driver.owner = owner; 132e7818584SSudeep Holla driver->driver.mod_name = mod_name; 133e7818584SSudeep Holla 134e7818584SSudeep Holla ret = driver_register(&driver->driver); 135e7818584SSudeep Holla if (!ret) 136e7818584SSudeep Holla pr_debug("registered new ffa driver %s\n", driver->name); 137e7818584SSudeep Holla 138e7818584SSudeep Holla return ret; 139e7818584SSudeep Holla } 140e7818584SSudeep Holla EXPORT_SYMBOL_GPL(ffa_driver_register); 141e7818584SSudeep Holla 142e7818584SSudeep Holla void ffa_driver_unregister(struct ffa_driver *driver) 143e7818584SSudeep Holla { 144e7818584SSudeep Holla driver_unregister(&driver->driver); 145e7818584SSudeep Holla } 146e7818584SSudeep Holla EXPORT_SYMBOL_GPL(ffa_driver_unregister); 147e7818584SSudeep Holla 148e7818584SSudeep Holla static void ffa_release_device(struct device *dev) 149e7818584SSudeep Holla { 150e7818584SSudeep Holla struct ffa_device *ffa_dev = to_ffa_dev(dev); 151e7818584SSudeep Holla 15219b87664SSudeep Holla ida_free(&ffa_bus_id, ffa_dev->id); 153e7818584SSudeep Holla kfree(ffa_dev); 154e7818584SSudeep Holla } 155e7818584SSudeep Holla 156e7818584SSudeep Holla static int __ffa_devices_unregister(struct device *dev, void *data) 157e7818584SSudeep Holla { 158eb7b52e6SSudeep Holla device_unregister(dev); 159e7818584SSudeep Holla 160e7818584SSudeep Holla return 0; 161e7818584SSudeep Holla } 162e7818584SSudeep Holla 163e7818584SSudeep Holla static void ffa_devices_unregister(void) 164e7818584SSudeep Holla { 165e7818584SSudeep Holla bus_for_each_dev(&ffa_bus_type, NULL, NULL, 166e7818584SSudeep Holla __ffa_devices_unregister); 167e7818584SSudeep Holla } 168e7818584SSudeep Holla 169e7818584SSudeep Holla bool ffa_device_is_valid(struct ffa_device *ffa_dev) 170e7818584SSudeep Holla { 171e7818584SSudeep Holla bool valid = false; 172e7818584SSudeep Holla struct device *dev = NULL; 173e7818584SSudeep Holla struct ffa_device *tmp_dev; 174e7818584SSudeep Holla 175e7818584SSudeep Holla do { 176e7818584SSudeep Holla dev = bus_find_next_device(&ffa_bus_type, dev); 177e7818584SSudeep Holla tmp_dev = to_ffa_dev(dev); 178e7818584SSudeep Holla if (tmp_dev == ffa_dev) { 179e7818584SSudeep Holla valid = true; 180e7818584SSudeep Holla break; 181e7818584SSudeep Holla } 182e7818584SSudeep Holla put_device(dev); 183e7818584SSudeep Holla } while (dev); 184e7818584SSudeep Holla 185e7818584SSudeep Holla put_device(dev); 186e7818584SSudeep Holla 187e7818584SSudeep Holla return valid; 188e7818584SSudeep Holla } 189e7818584SSudeep Holla 190d01387fcSSudeep Holla struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id, 1917aa7a979SSudeep Holla const struct ffa_ops *ops) 192e7818584SSudeep Holla { 19319b87664SSudeep Holla int id, ret; 194e7818584SSudeep Holla struct device *dev; 195e7818584SSudeep Holla struct ffa_device *ffa_dev; 196e7818584SSudeep Holla 19719b87664SSudeep Holla id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL); 19819b87664SSudeep Holla if (id < 0) 199e7818584SSudeep Holla return NULL; 200e7818584SSudeep Holla 20119b87664SSudeep Holla ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL); 20219b87664SSudeep Holla if (!ffa_dev) { 20319b87664SSudeep Holla ida_free(&ffa_bus_id, id); 20419b87664SSudeep Holla return NULL; 20519b87664SSudeep Holla } 20619b87664SSudeep Holla 207e7818584SSudeep Holla dev = &ffa_dev->dev; 208e7818584SSudeep Holla dev->bus = &ffa_bus_type; 209e7818584SSudeep Holla dev->release = ffa_release_device; 21019b87664SSudeep Holla dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id); 211e7818584SSudeep Holla 2127d0bc636SSudeep Holla ffa_dev->id = id; 213e7818584SSudeep Holla ffa_dev->vm_id = vm_id; 214d01387fcSSudeep Holla ffa_dev->ops = ops; 215e7818584SSudeep Holla uuid_copy(&ffa_dev->uuid, uuid); 216e7818584SSudeep Holla 217e7818584SSudeep Holla ret = device_register(&ffa_dev->dev); 218e7818584SSudeep Holla if (ret) { 219e7818584SSudeep Holla dev_err(dev, "unable to register device %s err=%d\n", 220e7818584SSudeep Holla dev_name(dev), ret); 221e7818584SSudeep Holla put_device(dev); 222e7818584SSudeep Holla return NULL; 223e7818584SSudeep Holla } 224e7818584SSudeep Holla 225e7818584SSudeep Holla return ffa_dev; 226e7818584SSudeep Holla } 227e7818584SSudeep Holla EXPORT_SYMBOL_GPL(ffa_device_register); 228e7818584SSudeep Holla 229e7818584SSudeep Holla void ffa_device_unregister(struct ffa_device *ffa_dev) 230e7818584SSudeep Holla { 231e7818584SSudeep Holla if (!ffa_dev) 232e7818584SSudeep Holla return; 233e7818584SSudeep Holla 234e7818584SSudeep Holla device_unregister(&ffa_dev->dev); 235e7818584SSudeep Holla } 236e7818584SSudeep Holla EXPORT_SYMBOL_GPL(ffa_device_unregister); 237e7818584SSudeep Holla 2383bbfe987SSudeep Holla int arm_ffa_bus_init(void) 239e7818584SSudeep Holla { 240e7818584SSudeep Holla return bus_register(&ffa_bus_type); 241e7818584SSudeep Holla } 242e7818584SSudeep Holla 2433bbfe987SSudeep Holla void arm_ffa_bus_exit(void) 244e7818584SSudeep Holla { 245e7818584SSudeep Holla ffa_devices_unregister(); 246e7818584SSudeep Holla bus_unregister(&ffa_bus_type); 24719b87664SSudeep Holla ida_destroy(&ffa_bus_id); 248e7818584SSudeep Holla } 249