linux/drivers/firmware/arm_ffa/bus.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2021 ARM Ltd.
   4 */
   5
   6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   7
   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
  18static int ffa_device_match(struct device *dev, struct device_driver *drv)
  19{
  20        const struct ffa_device_id *id_table;
  21        struct ffa_device *ffa_dev;
  22
  23        id_table = to_ffa_driver(drv)->id_table;
  24        ffa_dev = to_ffa_dev(dev);
  25
  26        while (!uuid_is_null(&id_table->uuid)) {
  27                /*
  28                 * FF-A v1.0 doesn't provide discovery of UUIDs, just the
  29                 * partition IDs, so fetch the partitions IDs for this
  30                 * id_table UUID and assign the UUID to the device if the
  31                 * partition ID matches
  32                 */
  33                if (uuid_is_null(&ffa_dev->uuid))
  34                        ffa_device_match_uuid(ffa_dev, &id_table->uuid);
  35
  36                if (uuid_equal(&ffa_dev->uuid, &id_table->uuid))
  37                        return 1;
  38                id_table++;
  39        }
  40
  41        return 0;
  42}
  43
  44static int ffa_device_probe(struct device *dev)
  45{
  46        struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
  47        struct ffa_device *ffa_dev = to_ffa_dev(dev);
  48
  49        return ffa_drv->probe(ffa_dev);
  50}
  51
  52static void ffa_device_remove(struct device *dev)
  53{
  54        struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
  55
  56        ffa_drv->remove(to_ffa_dev(dev));
  57}
  58
  59static int ffa_device_uevent(struct device *dev, struct kobj_uevent_env *env)
  60{
  61        struct ffa_device *ffa_dev = to_ffa_dev(dev);
  62
  63        return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb",
  64                              ffa_dev->vm_id, &ffa_dev->uuid);
  65}
  66
  67static ssize_t partition_id_show(struct device *dev,
  68                                 struct device_attribute *attr, char *buf)
  69{
  70        struct ffa_device *ffa_dev = to_ffa_dev(dev);
  71
  72        return sprintf(buf, "0x%04x\n", ffa_dev->vm_id);
  73}
  74static DEVICE_ATTR_RO(partition_id);
  75
  76static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
  77                         char *buf)
  78{
  79        struct ffa_device *ffa_dev = to_ffa_dev(dev);
  80
  81        return sprintf(buf, "%pUb\n", &ffa_dev->uuid);
  82}
  83static DEVICE_ATTR_RO(uuid);
  84
  85static struct attribute *ffa_device_attributes_attrs[] = {
  86        &dev_attr_partition_id.attr,
  87        &dev_attr_uuid.attr,
  88        NULL,
  89};
  90ATTRIBUTE_GROUPS(ffa_device_attributes);
  91
  92struct bus_type ffa_bus_type = {
  93        .name           = "arm_ffa",
  94        .match          = ffa_device_match,
  95        .probe          = ffa_device_probe,
  96        .remove         = ffa_device_remove,
  97        .uevent         = ffa_device_uevent,
  98        .dev_groups     = ffa_device_attributes_groups,
  99};
 100EXPORT_SYMBOL_GPL(ffa_bus_type);
 101
 102int ffa_driver_register(struct ffa_driver *driver, struct module *owner,
 103                        const char *mod_name)
 104{
 105        int ret;
 106
 107        if (!driver->probe)
 108                return -EINVAL;
 109
 110        driver->driver.bus = &ffa_bus_type;
 111        driver->driver.name = driver->name;
 112        driver->driver.owner = owner;
 113        driver->driver.mod_name = mod_name;
 114
 115        ret = driver_register(&driver->driver);
 116        if (!ret)
 117                pr_debug("registered new ffa driver %s\n", driver->name);
 118
 119        return ret;
 120}
 121EXPORT_SYMBOL_GPL(ffa_driver_register);
 122
 123void ffa_driver_unregister(struct ffa_driver *driver)
 124{
 125        driver_unregister(&driver->driver);
 126}
 127EXPORT_SYMBOL_GPL(ffa_driver_unregister);
 128
 129static void ffa_release_device(struct device *dev)
 130{
 131        struct ffa_device *ffa_dev = to_ffa_dev(dev);
 132
 133        kfree(ffa_dev);
 134}
 135
 136static int __ffa_devices_unregister(struct device *dev, void *data)
 137{
 138        device_unregister(dev);
 139
 140        return 0;
 141}
 142
 143static void ffa_devices_unregister(void)
 144{
 145        bus_for_each_dev(&ffa_bus_type, NULL, NULL,
 146                         __ffa_devices_unregister);
 147}
 148
 149bool ffa_device_is_valid(struct ffa_device *ffa_dev)
 150{
 151        bool valid = false;
 152        struct device *dev = NULL;
 153        struct ffa_device *tmp_dev;
 154
 155        do {
 156                dev = bus_find_next_device(&ffa_bus_type, dev);
 157                tmp_dev = to_ffa_dev(dev);
 158                if (tmp_dev == ffa_dev) {
 159                        valid = true;
 160                        break;
 161                }
 162                put_device(dev);
 163        } while (dev);
 164
 165        put_device(dev);
 166
 167        return valid;
 168}
 169
 170struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id)
 171{
 172        int ret;
 173        struct device *dev;
 174        struct ffa_device *ffa_dev;
 175
 176        ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL);
 177        if (!ffa_dev)
 178                return NULL;
 179
 180        dev = &ffa_dev->dev;
 181        dev->bus = &ffa_bus_type;
 182        dev->release = ffa_release_device;
 183        dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id);
 184
 185        ffa_dev->vm_id = vm_id;
 186        uuid_copy(&ffa_dev->uuid, uuid);
 187
 188        ret = device_register(&ffa_dev->dev);
 189        if (ret) {
 190                dev_err(dev, "unable to register device %s err=%d\n",
 191                        dev_name(dev), ret);
 192                put_device(dev);
 193                return NULL;
 194        }
 195
 196        return ffa_dev;
 197}
 198EXPORT_SYMBOL_GPL(ffa_device_register);
 199
 200void ffa_device_unregister(struct ffa_device *ffa_dev)
 201{
 202        if (!ffa_dev)
 203                return;
 204
 205        device_unregister(&ffa_dev->dev);
 206}
 207EXPORT_SYMBOL_GPL(ffa_device_unregister);
 208
 209int arm_ffa_bus_init(void)
 210{
 211        return bus_register(&ffa_bus_type);
 212}
 213
 214void arm_ffa_bus_exit(void)
 215{
 216        ffa_devices_unregister();
 217        bus_unregister(&ffa_bus_type);
 218}
 219