1
2
3
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
29
30
31
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