xref: /linux/drivers/firmware/arm_ffa/bus.c (revision dd3802fc4f6b52201a93330d44981a66bd6ef883)
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