brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · eb17d03 Raw
256 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2021 ARM Ltd.4 */5 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt7 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 the33		 * partition IDs, so match it unconditionally here and handle34		 * 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 *ffa_device_register(const uuid_t *uuid, int vm_id,191				       const struct ffa_ops *ops)192{193	int id, ret;194	struct device *dev;195	struct ffa_device *ffa_dev;196 197	id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL);198	if (id < 0)199		return NULL;200 201	ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL);202	if (!ffa_dev) {203		ida_free(&ffa_bus_id, id);204		return NULL;205	}206 207	dev = &ffa_dev->dev;208	dev->bus = &ffa_bus_type;209	dev->release = ffa_release_device;210	dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);211 212	ffa_dev->id = id;213	ffa_dev->vm_id = vm_id;214	ffa_dev->ops = ops;215	uuid_copy(&ffa_dev->uuid, uuid);216 217	ret = device_register(&ffa_dev->dev);218	if (ret) {219		dev_err(dev, "unable to register device %s err=%d\n",220			dev_name(dev), ret);221		put_device(dev);222		return NULL;223	}224 225	return ffa_dev;226}227EXPORT_SYMBOL_GPL(ffa_device_register);228 229void ffa_device_unregister(struct ffa_device *ffa_dev)230{231	if (!ffa_dev)232		return;233 234	device_unregister(&ffa_dev->dev);235}236EXPORT_SYMBOL_GPL(ffa_device_unregister);237 238static int __init arm_ffa_bus_init(void)239{240	return bus_register(&ffa_bus_type);241}242subsys_initcall(arm_ffa_bus_init);243 244static void __exit arm_ffa_bus_exit(void)245{246	ffa_devices_unregister();247	bus_unregister(&ffa_bus_type);248	ida_destroy(&ffa_bus_id);249}250module_exit(arm_ffa_bus_exit);251 252MODULE_ALIAS("ffa-core");253MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");254MODULE_DESCRIPTION("ARM FF-A bus");255MODULE_LICENSE("GPL");256