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