1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2021 ARM Ltd.
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8 #include <linux/arm_ffa.h>
9 #include <linux/device.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/slab.h>
14 #include <linux/types.h>
18 static int ffa_device_match(struct device *dev, struct device_driver *drv)
20 const struct ffa_device_id *id_table;
21 struct ffa_device *ffa_dev;
23 id_table = to_ffa_driver(drv)->id_table;
24 ffa_dev = to_ffa_dev(dev);
26 while (!uuid_is_null(&id_table->uuid)) {
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
33 if (uuid_is_null(&ffa_dev->uuid))
34 ffa_device_match_uuid(ffa_dev, &id_table->uuid);
36 if (uuid_equal(&ffa_dev->uuid, &id_table->uuid))
44 static int ffa_device_probe(struct device *dev)
46 struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
47 struct ffa_device *ffa_dev = to_ffa_dev(dev);
49 return ffa_drv->probe(ffa_dev);
52 static void ffa_device_remove(struct device *dev)
54 struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
56 ffa_drv->remove(to_ffa_dev(dev));
59 static int ffa_device_uevent(struct device *dev, struct kobj_uevent_env *env)
61 struct ffa_device *ffa_dev = to_ffa_dev(dev);
63 return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb",
64 ffa_dev->vm_id, &ffa_dev->uuid);
67 static ssize_t partition_id_show(struct device *dev,
68 struct device_attribute *attr, char *buf)
70 struct ffa_device *ffa_dev = to_ffa_dev(dev);
72 return sprintf(buf, "0x%04x\n", ffa_dev->vm_id);
74 static DEVICE_ATTR_RO(partition_id);
76 static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
79 struct ffa_device *ffa_dev = to_ffa_dev(dev);
81 return sprintf(buf, "%pUb\n", &ffa_dev->uuid);
83 static DEVICE_ATTR_RO(uuid);
85 static struct attribute *ffa_device_attributes_attrs[] = {
86 &dev_attr_partition_id.attr,
90 ATTRIBUTE_GROUPS(ffa_device_attributes);
92 struct bus_type ffa_bus_type = {
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,
100 EXPORT_SYMBOL_GPL(ffa_bus_type);
102 int ffa_driver_register(struct ffa_driver *driver, struct module *owner,
103 const char *mod_name)
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;
115 ret = driver_register(&driver->driver);
117 pr_debug("registered new ffa driver %s\n", driver->name);
121 EXPORT_SYMBOL_GPL(ffa_driver_register);
123 void ffa_driver_unregister(struct ffa_driver *driver)
125 driver_unregister(&driver->driver);
127 EXPORT_SYMBOL_GPL(ffa_driver_unregister);
129 static void ffa_release_device(struct device *dev)
131 struct ffa_device *ffa_dev = to_ffa_dev(dev);
136 static int __ffa_devices_unregister(struct device *dev, void *data)
138 device_unregister(dev);
143 static void ffa_devices_unregister(void)
145 bus_for_each_dev(&ffa_bus_type, NULL, NULL,
146 __ffa_devices_unregister);
149 bool ffa_device_is_valid(struct ffa_device *ffa_dev)
152 struct device *dev = NULL;
153 struct ffa_device *tmp_dev;
156 dev = bus_find_next_device(&ffa_bus_type, dev);
157 tmp_dev = to_ffa_dev(dev);
158 if (tmp_dev == ffa_dev) {
170 struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id)
174 struct ffa_device *ffa_dev;
176 ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL);
181 dev->bus = &ffa_bus_type;
182 dev->release = ffa_release_device;
183 dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id);
185 ffa_dev->vm_id = vm_id;
186 uuid_copy(&ffa_dev->uuid, uuid);
188 ret = device_register(&ffa_dev->dev);
190 dev_err(dev, "unable to register device %s err=%d\n",
198 EXPORT_SYMBOL_GPL(ffa_device_register);
200 void ffa_device_unregister(struct ffa_device *ffa_dev)
205 device_unregister(&ffa_dev->dev);
207 EXPORT_SYMBOL_GPL(ffa_device_unregister);
209 int arm_ffa_bus_init(void)
211 return bus_register(&ffa_bus_type);
214 void arm_ffa_bus_exit(void)
216 ffa_devices_unregister();
217 bus_unregister(&ffa_bus_type);