mirror of
https://github.com/torvalds/linux.git
synced 2024-11-29 23:51:37 +00:00
c2a96b7f18
Here is the big set of driver core changes for 6.11-rc1. Lots of stuff in here, with not a huge diffstat, but apis are evolving which required lots of files to be touched. Highlights of the changes in here are: - platform remove callback api final fixups (Uwe took many releases to get here, finally!) - Rust bindings for basic firmware apis and initial driver-core interactions. It's not all that useful for a "write a whole driver in rust" type of thing, but the firmware bindings do help out the phy rust drivers, and the driver core bindings give a solid base on which others can start their work. There is still a long way to go here before we have a multitude of rust drivers being added, but it's a great first step. - driver core const api changes. This reached across all bus types, and there are some fix-ups for some not-common bus types that linux-next and 0-day testing shook out. This work is being done to help make the rust bindings more safe, as well as the C code, moving toward the end-goal of allowing us to put driver structures into read-only memory. We aren't there yet, but are getting closer. - minor devres cleanups and fixes found by code inspection - arch_topology minor changes - other minor driver core cleanups All of these have been in linux-next for a very long time with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZqH+aQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymoOQCfVBdLcBjEDAGh3L8qHRGMPy4rV2EAoL/r+zKm cJEYtJpGtWX6aAtugm9E =ZyJV -----END PGP SIGNATURE----- Merge tag 'driver-core-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core updates from Greg KH: "Here is the big set of driver core changes for 6.11-rc1. Lots of stuff in here, with not a huge diffstat, but apis are evolving which required lots of files to be touched. Highlights of the changes in here are: - platform remove callback api final fixups (Uwe took many releases to get here, finally!) - Rust bindings for basic firmware apis and initial driver-core interactions. It's not all that useful for a "write a whole driver in rust" type of thing, but the firmware bindings do help out the phy rust drivers, and the driver core bindings give a solid base on which others can start their work. There is still a long way to go here before we have a multitude of rust drivers being added, but it's a great first step. - driver core const api changes. This reached across all bus types, and there are some fix-ups for some not-common bus types that linux-next and 0-day testing shook out. This work is being done to help make the rust bindings more safe, as well as the C code, moving toward the end-goal of allowing us to put driver structures into read-only memory. We aren't there yet, but are getting closer. - minor devres cleanups and fixes found by code inspection - arch_topology minor changes - other minor driver core cleanups All of these have been in linux-next for a very long time with no reported problems" * tag 'driver-core-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (55 commits) ARM: sa1100: make match function take a const pointer sysfs/cpu: Make crash_hotplug attribute world-readable dio: Have dio_bus_match() callback take a const * zorro: make match function take a const pointer driver core: module: make module_[add|remove]_driver take a const * driver core: make driver_find_device() take a const * driver core: make driver_[create|remove]_file take a const * firmware_loader: fix soundness issue in `request_internal` firmware_loader: annotate doctests as `no_run` devres: Correct code style for functions that return a pointer type devres: Initialize an uninitialized struct member devres: Fix memory leakage caused by driver API devm_free_percpu() devres: Fix devm_krealloc() wasting memory driver core: platform: Switch to use kmemdup_array() driver core: have match() callback in struct bus_type take a const * MAINTAINERS: add Rust device abstractions to DRIVER CORE device: rust: improve safety comments MAINTAINERS: add Danilo as FIRMWARE LOADER maintainer MAINTAINERS: add Rust FW abstractions to FIRMWARE LOADER firmware: rust: improve safety comments ...
256 lines
5.6 KiB
C
256 lines
5.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2021 ARM Ltd.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/arm_ffa.h>
|
|
#include <linux/device.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/types.h>
|
|
|
|
#include "common.h"
|
|
|
|
#define SCMI_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb"
|
|
|
|
static DEFINE_IDA(ffa_bus_id);
|
|
|
|
static int ffa_device_match(struct device *dev, const struct device_driver *drv)
|
|
{
|
|
const struct ffa_device_id *id_table;
|
|
struct ffa_device *ffa_dev;
|
|
|
|
id_table = to_ffa_driver(drv)->id_table;
|
|
ffa_dev = to_ffa_dev(dev);
|
|
|
|
while (!uuid_is_null(&id_table->uuid)) {
|
|
/*
|
|
* FF-A v1.0 doesn't provide discovery of UUIDs, just the
|
|
* partition IDs, so match it unconditionally here and handle
|
|
* it via the installed bus notifier during driver binding.
|
|
*/
|
|
if (uuid_is_null(&ffa_dev->uuid))
|
|
return 1;
|
|
|
|
if (uuid_equal(&ffa_dev->uuid, &id_table->uuid))
|
|
return 1;
|
|
id_table++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ffa_device_probe(struct device *dev)
|
|
{
|
|
struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
|
|
struct ffa_device *ffa_dev = to_ffa_dev(dev);
|
|
|
|
/* UUID can be still NULL with FF-A v1.0, so just skip probing them */
|
|
if (uuid_is_null(&ffa_dev->uuid))
|
|
return -ENODEV;
|
|
|
|
return ffa_drv->probe(ffa_dev);
|
|
}
|
|
|
|
static void ffa_device_remove(struct device *dev)
|
|
{
|
|
struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
|
|
|
|
if (ffa_drv->remove)
|
|
ffa_drv->remove(to_ffa_dev(dev));
|
|
}
|
|
|
|
static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
|
|
{
|
|
const struct ffa_device *ffa_dev = to_ffa_dev(dev);
|
|
|
|
return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT,
|
|
ffa_dev->vm_id, &ffa_dev->uuid);
|
|
}
|
|
|
|
static ssize_t modalias_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct ffa_device *ffa_dev = to_ffa_dev(dev);
|
|
|
|
return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id,
|
|
&ffa_dev->uuid);
|
|
}
|
|
static DEVICE_ATTR_RO(modalias);
|
|
|
|
static ssize_t partition_id_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct ffa_device *ffa_dev = to_ffa_dev(dev);
|
|
|
|
return sprintf(buf, "0x%04x\n", ffa_dev->vm_id);
|
|
}
|
|
static DEVICE_ATTR_RO(partition_id);
|
|
|
|
static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct ffa_device *ffa_dev = to_ffa_dev(dev);
|
|
|
|
return sprintf(buf, "%pUb\n", &ffa_dev->uuid);
|
|
}
|
|
static DEVICE_ATTR_RO(uuid);
|
|
|
|
static struct attribute *ffa_device_attributes_attrs[] = {
|
|
&dev_attr_partition_id.attr,
|
|
&dev_attr_uuid.attr,
|
|
&dev_attr_modalias.attr,
|
|
NULL,
|
|
};
|
|
ATTRIBUTE_GROUPS(ffa_device_attributes);
|
|
|
|
const struct bus_type ffa_bus_type = {
|
|
.name = "arm_ffa",
|
|
.match = ffa_device_match,
|
|
.probe = ffa_device_probe,
|
|
.remove = ffa_device_remove,
|
|
.uevent = ffa_device_uevent,
|
|
.dev_groups = ffa_device_attributes_groups,
|
|
};
|
|
EXPORT_SYMBOL_GPL(ffa_bus_type);
|
|
|
|
int ffa_driver_register(struct ffa_driver *driver, struct module *owner,
|
|
const char *mod_name)
|
|
{
|
|
int ret;
|
|
|
|
if (!driver->probe)
|
|
return -EINVAL;
|
|
|
|
driver->driver.bus = &ffa_bus_type;
|
|
driver->driver.name = driver->name;
|
|
driver->driver.owner = owner;
|
|
driver->driver.mod_name = mod_name;
|
|
|
|
ret = driver_register(&driver->driver);
|
|
if (!ret)
|
|
pr_debug("registered new ffa driver %s\n", driver->name);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(ffa_driver_register);
|
|
|
|
void ffa_driver_unregister(struct ffa_driver *driver)
|
|
{
|
|
driver_unregister(&driver->driver);
|
|
}
|
|
EXPORT_SYMBOL_GPL(ffa_driver_unregister);
|
|
|
|
static void ffa_release_device(struct device *dev)
|
|
{
|
|
struct ffa_device *ffa_dev = to_ffa_dev(dev);
|
|
|
|
ida_free(&ffa_bus_id, ffa_dev->id);
|
|
kfree(ffa_dev);
|
|
}
|
|
|
|
static int __ffa_devices_unregister(struct device *dev, void *data)
|
|
{
|
|
device_unregister(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ffa_devices_unregister(void)
|
|
{
|
|
bus_for_each_dev(&ffa_bus_type, NULL, NULL,
|
|
__ffa_devices_unregister);
|
|
}
|
|
|
|
bool ffa_device_is_valid(struct ffa_device *ffa_dev)
|
|
{
|
|
bool valid = false;
|
|
struct device *dev = NULL;
|
|
struct ffa_device *tmp_dev;
|
|
|
|
do {
|
|
dev = bus_find_next_device(&ffa_bus_type, dev);
|
|
tmp_dev = to_ffa_dev(dev);
|
|
if (tmp_dev == ffa_dev) {
|
|
valid = true;
|
|
break;
|
|
}
|
|
put_device(dev);
|
|
} while (dev);
|
|
|
|
put_device(dev);
|
|
|
|
return valid;
|
|
}
|
|
|
|
struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id,
|
|
const struct ffa_ops *ops)
|
|
{
|
|
int id, ret;
|
|
struct device *dev;
|
|
struct ffa_device *ffa_dev;
|
|
|
|
id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL);
|
|
if (id < 0)
|
|
return NULL;
|
|
|
|
ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL);
|
|
if (!ffa_dev) {
|
|
ida_free(&ffa_bus_id, id);
|
|
return NULL;
|
|
}
|
|
|
|
dev = &ffa_dev->dev;
|
|
dev->bus = &ffa_bus_type;
|
|
dev->release = ffa_release_device;
|
|
dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);
|
|
|
|
ffa_dev->id = id;
|
|
ffa_dev->vm_id = vm_id;
|
|
ffa_dev->ops = ops;
|
|
uuid_copy(&ffa_dev->uuid, uuid);
|
|
|
|
ret = device_register(&ffa_dev->dev);
|
|
if (ret) {
|
|
dev_err(dev, "unable to register device %s err=%d\n",
|
|
dev_name(dev), ret);
|
|
put_device(dev);
|
|
return NULL;
|
|
}
|
|
|
|
return ffa_dev;
|
|
}
|
|
EXPORT_SYMBOL_GPL(ffa_device_register);
|
|
|
|
void ffa_device_unregister(struct ffa_device *ffa_dev)
|
|
{
|
|
if (!ffa_dev)
|
|
return;
|
|
|
|
device_unregister(&ffa_dev->dev);
|
|
}
|
|
EXPORT_SYMBOL_GPL(ffa_device_unregister);
|
|
|
|
static int __init arm_ffa_bus_init(void)
|
|
{
|
|
return bus_register(&ffa_bus_type);
|
|
}
|
|
subsys_initcall(arm_ffa_bus_init);
|
|
|
|
static void __exit arm_ffa_bus_exit(void)
|
|
{
|
|
ffa_devices_unregister();
|
|
bus_unregister(&ffa_bus_type);
|
|
ida_destroy(&ffa_bus_id);
|
|
}
|
|
module_exit(arm_ffa_bus_exit);
|
|
|
|
MODULE_ALIAS("ffa-core");
|
|
MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
|
|
MODULE_DESCRIPTION("ARM FF-A bus");
|
|
MODULE_LICENSE("GPL");
|