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