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