Linux Audio

Check our new training course

Embedded Linux training

Mar 31-Apr 8, 2025
Register
Loading...
Note: File does not exist in v4.6.
  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
 20static DEFINE_IDA(ffa_bus_id);
 21
 22static 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
 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 match it unconditionally here and handle
 34		 * it via the installed bus notifier during driver binding.
 35		 */
 36		if (uuid_is_null(&ffa_dev->uuid))
 37			return 1;
 38
 39		if (uuid_equal(&ffa_dev->uuid, &id_table->uuid))
 40			return 1;
 41		id_table++;
 42	}
 43
 44	return 0;
 45}
 46
 47static int ffa_device_probe(struct device *dev)
 48{
 49	struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
 50	struct ffa_device *ffa_dev = to_ffa_dev(dev);
 51
 52	/* UUID can be still NULL with FF-A v1.0, so just skip probing them */
 53	if (uuid_is_null(&ffa_dev->uuid))
 54		return -ENODEV;
 55
 56	return ffa_drv->probe(ffa_dev);
 57}
 58
 59static void ffa_device_remove(struct device *dev)
 60{
 61	struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
 62
 63	if (ffa_drv->remove)
 64		ffa_drv->remove(to_ffa_dev(dev));
 65}
 66
 67static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
 68{
 69	const struct ffa_device *ffa_dev = to_ffa_dev(dev);
 70
 71	return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT,
 72			      ffa_dev->vm_id, &ffa_dev->uuid);
 73}
 74
 75static ssize_t modalias_show(struct device *dev,
 76			     struct device_attribute *attr, char *buf)
 77{
 78	struct ffa_device *ffa_dev = to_ffa_dev(dev);
 79
 80	return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id,
 81			  &ffa_dev->uuid);
 82}
 83static DEVICE_ATTR_RO(modalias);
 84
 85static ssize_t partition_id_show(struct device *dev,
 86				 struct device_attribute *attr, char *buf)
 87{
 88	struct ffa_device *ffa_dev = to_ffa_dev(dev);
 89
 90	return sprintf(buf, "0x%04x\n", ffa_dev->vm_id);
 91}
 92static DEVICE_ATTR_RO(partition_id);
 93
 94static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
 95			 char *buf)
 96{
 97	struct ffa_device *ffa_dev = to_ffa_dev(dev);
 98
 99	return sprintf(buf, "%pUb\n", &ffa_dev->uuid);
100}
101static DEVICE_ATTR_RO(uuid);
102
103static struct attribute *ffa_device_attributes_attrs[] = {
104	&dev_attr_partition_id.attr,
105	&dev_attr_uuid.attr,
106	&dev_attr_modalias.attr,
107	NULL,
108};
109ATTRIBUTE_GROUPS(ffa_device_attributes);
110
111const struct bus_type ffa_bus_type = {
112	.name		= "arm_ffa",
113	.match		= ffa_device_match,
114	.probe		= ffa_device_probe,
115	.remove		= ffa_device_remove,
116	.uevent		= ffa_device_uevent,
117	.dev_groups	= ffa_device_attributes_groups,
118};
119EXPORT_SYMBOL_GPL(ffa_bus_type);
120
121int ffa_driver_register(struct ffa_driver *driver, struct module *owner,
122			const char *mod_name)
123{
124	int ret;
125
126	if (!driver->probe)
127		return -EINVAL;
128
129	driver->driver.bus = &ffa_bus_type;
130	driver->driver.name = driver->name;
131	driver->driver.owner = owner;
132	driver->driver.mod_name = mod_name;
133
134	ret = driver_register(&driver->driver);
135	if (!ret)
136		pr_debug("registered new ffa driver %s\n", driver->name);
137
138	return ret;
139}
140EXPORT_SYMBOL_GPL(ffa_driver_register);
141
142void ffa_driver_unregister(struct ffa_driver *driver)
143{
144	driver_unregister(&driver->driver);
145}
146EXPORT_SYMBOL_GPL(ffa_driver_unregister);
147
148static void ffa_release_device(struct device *dev)
149{
150	struct ffa_device *ffa_dev = to_ffa_dev(dev);
151
152	ida_free(&ffa_bus_id, ffa_dev->id);
153	kfree(ffa_dev);
154}
155
156static int __ffa_devices_unregister(struct device *dev, void *data)
157{
158	device_unregister(dev);
159
160	return 0;
161}
162
163static void ffa_devices_unregister(void)
164{
165	bus_for_each_dev(&ffa_bus_type, NULL, NULL,
166			 __ffa_devices_unregister);
167}
168
169bool ffa_device_is_valid(struct ffa_device *ffa_dev)
170{
171	bool valid = false;
172	struct device *dev = NULL;
173	struct ffa_device *tmp_dev;
174
175	do {
176		dev = bus_find_next_device(&ffa_bus_type, dev);
177		tmp_dev = to_ffa_dev(dev);
178		if (tmp_dev == ffa_dev) {
179			valid = true;
180			break;
181		}
182		put_device(dev);
183	} while (dev);
184
185	put_device(dev);
186
187	return valid;
188}
189
190struct ffa_device *
191ffa_device_register(const struct ffa_partition_info *part_info,
192		    const struct ffa_ops *ops)
193{
194	int id, ret;
195	uuid_t uuid;
196	struct device *dev;
197	struct ffa_device *ffa_dev;
198
199	if (!part_info)
200		return NULL;
201
202	id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL);
203	if (id < 0)
204		return NULL;
205
206	ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL);
207	if (!ffa_dev) {
208		ida_free(&ffa_bus_id, id);
209		return NULL;
210	}
211
212	dev = &ffa_dev->dev;
213	dev->bus = &ffa_bus_type;
214	dev->release = ffa_release_device;
215	dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);
216
217	ffa_dev->id = id;
218	ffa_dev->vm_id = part_info->id;
219	ffa_dev->properties = part_info->properties;
220	ffa_dev->ops = ops;
221	import_uuid(&uuid, (u8 *)part_info->uuid);
222	uuid_copy(&ffa_dev->uuid, &uuid);
223
224	ret = device_register(&ffa_dev->dev);
225	if (ret) {
226		dev_err(dev, "unable to register device %s err=%d\n",
227			dev_name(dev), ret);
228		put_device(dev);
229		return NULL;
230	}
231
232	return ffa_dev;
233}
234EXPORT_SYMBOL_GPL(ffa_device_register);
235
236void ffa_device_unregister(struct ffa_device *ffa_dev)
237{
238	if (!ffa_dev)
239		return;
240
241	device_unregister(&ffa_dev->dev);
242}
243EXPORT_SYMBOL_GPL(ffa_device_unregister);
244
245static int __init arm_ffa_bus_init(void)
246{
247	return bus_register(&ffa_bus_type);
248}
249subsys_initcall(arm_ffa_bus_init);
250
251static void __exit arm_ffa_bus_exit(void)
252{
253	ffa_devices_unregister();
254	bus_unregister(&ffa_bus_type);
255	ida_destroy(&ffa_bus_id);
256}
257module_exit(arm_ffa_bus_exit);
258
259MODULE_ALIAS("ffa-core");
260MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
261MODULE_DESCRIPTION("ARM FF-A bus");
262MODULE_LICENSE("GPL");