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
18static DEFINE_IDA(ffa_bus_id);
19
20static 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
46static 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
54static 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
62static 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
70static 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}
77static DEVICE_ATTR_RO(partition_id);
78
79static 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}
86static DEVICE_ATTR_RO(uuid);
87
88static struct attribute *ffa_device_attributes_attrs[] = {
89	&dev_attr_partition_id.attr,
90	&dev_attr_uuid.attr,
91	NULL,
92};
93ATTRIBUTE_GROUPS(ffa_device_attributes);
94
95struct 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};
103EXPORT_SYMBOL_GPL(ffa_bus_type);
104
105int 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}
124EXPORT_SYMBOL_GPL(ffa_driver_register);
125
126void ffa_driver_unregister(struct ffa_driver *driver)
127{
128	driver_unregister(&driver->driver);
129}
130EXPORT_SYMBOL_GPL(ffa_driver_unregister);
131
132static 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
140static int __ffa_devices_unregister(struct device *dev, void *data)
141{
142	device_unregister(dev);
143
144	return 0;
145}
146
147static void ffa_devices_unregister(void)
148{
149	bus_for_each_dev(&ffa_bus_type, NULL, NULL,
150			 __ffa_devices_unregister);
151}
152
153bool 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
174struct 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}
211EXPORT_SYMBOL_GPL(ffa_device_register);
212
213void ffa_device_unregister(struct ffa_device *ffa_dev)
214{
215	if (!ffa_dev)
216		return;
217
218	device_unregister(&ffa_dev->dev);
219}
220EXPORT_SYMBOL_GPL(ffa_device_unregister);
221
222int arm_ffa_bus_init(void)
223{
224	return bus_register(&ffa_bus_type);
225}
226
227void arm_ffa_bus_exit(void)
228{
229	ffa_devices_unregister();
230	bus_unregister(&ffa_bus_type);
231	ida_destroy(&ffa_bus_id);
232}
233