mirror of
https://github.com/torvalds/linux.git
synced 2024-11-29 07:31:29 +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 ...
277 lines
10 KiB
C
277 lines
10 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2019-2020 Intel Corporation
|
|
*
|
|
* Please see Documentation/driver-api/auxiliary_bus.rst for more information.
|
|
*/
|
|
|
|
#ifndef _AUXILIARY_BUS_H_
|
|
#define _AUXILIARY_BUS_H_
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/mod_devicetable.h>
|
|
|
|
/**
|
|
* DOC: DEVICE_LIFESPAN
|
|
*
|
|
* The registering driver is the entity that allocates memory for the
|
|
* auxiliary_device and registers it on the auxiliary bus. It is important to
|
|
* note that, as opposed to the platform bus, the registering driver is wholly
|
|
* responsible for the management of the memory used for the device object.
|
|
*
|
|
* To be clear the memory for the auxiliary_device is freed in the release()
|
|
* callback defined by the registering driver. The registering driver should
|
|
* only call auxiliary_device_delete() and then auxiliary_device_uninit() when
|
|
* it is done with the device. The release() function is then automatically
|
|
* called if and when other code releases their reference to the devices.
|
|
*
|
|
* A parent object, defined in the shared header file, contains the
|
|
* auxiliary_device. It also contains a pointer to the shared object(s), which
|
|
* also is defined in the shared header. Both the parent object and the shared
|
|
* object(s) are allocated by the registering driver. This layout allows the
|
|
* auxiliary_driver's registering module to perform a container_of() call to go
|
|
* from the pointer to the auxiliary_device, that is passed during the call to
|
|
* the auxiliary_driver's probe function, up to the parent object, and then
|
|
* have access to the shared object(s).
|
|
*
|
|
* The memory for the shared object(s) must have a lifespan equal to, or
|
|
* greater than, the lifespan of the memory for the auxiliary_device. The
|
|
* auxiliary_driver should only consider that the shared object is valid as
|
|
* long as the auxiliary_device is still registered on the auxiliary bus. It
|
|
* is up to the registering driver to manage (e.g. free or keep available) the
|
|
* memory for the shared object beyond the life of the auxiliary_device.
|
|
*
|
|
* The registering driver must unregister all auxiliary devices before its own
|
|
* driver.remove() is completed. An easy way to ensure this is to use the
|
|
* devm_add_action_or_reset() call to register a function against the parent
|
|
* device which unregisters the auxiliary device object(s).
|
|
*
|
|
* Finally, any operations which operate on the auxiliary devices must continue
|
|
* to function (if only to return an error) after the registering driver
|
|
* unregisters the auxiliary device.
|
|
*/
|
|
|
|
/**
|
|
* struct auxiliary_device - auxiliary device object.
|
|
* @dev: Device,
|
|
* The release and parent fields of the device structure must be filled
|
|
* in
|
|
* @name: Match name found by the auxiliary device driver,
|
|
* @id: unique identitier if multiple devices of the same name are exported,
|
|
* @sysfs: embedded struct which hold all sysfs related fields,
|
|
* @sysfs.irqs: irqs xarray contains irq indices which are used by the device,
|
|
* @sysfs.lock: Synchronize irq sysfs creation,
|
|
* @sysfs.irq_dir_exists: whether "irqs" directory exists,
|
|
*
|
|
* An auxiliary_device represents a part of its parent device's functionality.
|
|
* It is given a name that, combined with the registering drivers
|
|
* KBUILD_MODNAME, creates a match_name that is used for driver binding, and an
|
|
* id that combined with the match_name provide a unique name to register with
|
|
* the bus subsystem. For example, a driver registering an auxiliary device is
|
|
* named 'foo_mod.ko' and the subdevice is named 'foo_dev'. The match name is
|
|
* therefore 'foo_mod.foo_dev'.
|
|
*
|
|
* Registering an auxiliary_device is a three-step process.
|
|
*
|
|
* First, a 'struct auxiliary_device' needs to be defined or allocated for each
|
|
* sub-device desired. The name, id, dev.release, and dev.parent fields of
|
|
* this structure must be filled in as follows.
|
|
*
|
|
* The 'name' field is to be given a name that is recognized by the auxiliary
|
|
* driver. If two auxiliary_devices with the same match_name, eg
|
|
* "foo_mod.foo_dev", are registered onto the bus, they must have unique id
|
|
* values (e.g. "x" and "y") so that the registered devices names are
|
|
* "foo_mod.foo_dev.x" and "foo_mod.foo_dev.y". If match_name + id are not
|
|
* unique, then the device_add fails and generates an error message.
|
|
*
|
|
* The auxiliary_device.dev.type.release or auxiliary_device.dev.release must
|
|
* be populated with a non-NULL pointer to successfully register the
|
|
* auxiliary_device. This release call is where resources associated with the
|
|
* auxiliary device must be free'ed. Because once the device is placed on the
|
|
* bus the parent driver can not tell what other code may have a reference to
|
|
* this data.
|
|
*
|
|
* The auxiliary_device.dev.parent should be set. Typically to the registering
|
|
* drivers device.
|
|
*
|
|
* Second, call auxiliary_device_init(), which checks several aspects of the
|
|
* auxiliary_device struct and performs a device_initialize(). After this step
|
|
* completes, any error state must have a call to auxiliary_device_uninit() in
|
|
* its resolution path.
|
|
*
|
|
* The third and final step in registering an auxiliary_device is to perform a
|
|
* call to auxiliary_device_add(), which sets the name of the device and adds
|
|
* the device to the bus.
|
|
*
|
|
* .. code-block:: c
|
|
*
|
|
* #define MY_DEVICE_NAME "foo_dev"
|
|
*
|
|
* ...
|
|
*
|
|
* struct auxiliary_device *my_aux_dev = my_aux_dev_alloc(xxx);
|
|
*
|
|
* // Step 1:
|
|
* my_aux_dev->name = MY_DEVICE_NAME;
|
|
* my_aux_dev->id = my_unique_id_alloc(xxx);
|
|
* my_aux_dev->dev.release = my_aux_dev_release;
|
|
* my_aux_dev->dev.parent = my_dev;
|
|
*
|
|
* // Step 2:
|
|
* if (auxiliary_device_init(my_aux_dev))
|
|
* goto fail;
|
|
*
|
|
* // Step 3:
|
|
* if (auxiliary_device_add(my_aux_dev)) {
|
|
* auxiliary_device_uninit(my_aux_dev);
|
|
* goto fail;
|
|
* }
|
|
*
|
|
* ...
|
|
*
|
|
*
|
|
* Unregistering an auxiliary_device is a two-step process to mirror the
|
|
* register process. First call auxiliary_device_delete(), then call
|
|
* auxiliary_device_uninit().
|
|
*
|
|
* .. code-block:: c
|
|
*
|
|
* auxiliary_device_delete(my_dev->my_aux_dev);
|
|
* auxiliary_device_uninit(my_dev->my_aux_dev);
|
|
*/
|
|
struct auxiliary_device {
|
|
struct device dev;
|
|
const char *name;
|
|
u32 id;
|
|
struct {
|
|
struct xarray irqs;
|
|
struct mutex lock; /* Synchronize irq sysfs creation */
|
|
bool irq_dir_exists;
|
|
} sysfs;
|
|
};
|
|
|
|
/**
|
|
* struct auxiliary_driver - Definition of an auxiliary bus driver
|
|
* @probe: Called when a matching device is added to the bus.
|
|
* @remove: Called when device is removed from the bus.
|
|
* @shutdown: Called at shut-down time to quiesce the device.
|
|
* @suspend: Called to put the device to sleep mode. Usually to a power state.
|
|
* @resume: Called to bring a device from sleep mode.
|
|
* @name: Driver name.
|
|
* @driver: Core driver structure.
|
|
* @id_table: Table of devices this driver should match on the bus.
|
|
*
|
|
* Auxiliary drivers follow the standard driver model convention, where
|
|
* discovery/enumeration is handled by the core, and drivers provide probe()
|
|
* and remove() methods. They support power management and shutdown
|
|
* notifications using the standard conventions.
|
|
*
|
|
* Auxiliary drivers register themselves with the bus by calling
|
|
* auxiliary_driver_register(). The id_table contains the match_names of
|
|
* auxiliary devices that a driver can bind with.
|
|
*
|
|
* .. code-block:: c
|
|
*
|
|
* static const struct auxiliary_device_id my_auxiliary_id_table[] = {
|
|
* { .name = "foo_mod.foo_dev" },
|
|
* {},
|
|
* };
|
|
*
|
|
* MODULE_DEVICE_TABLE(auxiliary, my_auxiliary_id_table);
|
|
*
|
|
* struct auxiliary_driver my_drv = {
|
|
* .name = "myauxiliarydrv",
|
|
* .id_table = my_auxiliary_id_table,
|
|
* .probe = my_drv_probe,
|
|
* .remove = my_drv_remove
|
|
* };
|
|
*/
|
|
struct auxiliary_driver {
|
|
int (*probe)(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id);
|
|
void (*remove)(struct auxiliary_device *auxdev);
|
|
void (*shutdown)(struct auxiliary_device *auxdev);
|
|
int (*suspend)(struct auxiliary_device *auxdev, pm_message_t state);
|
|
int (*resume)(struct auxiliary_device *auxdev);
|
|
const char *name;
|
|
struct device_driver driver;
|
|
const struct auxiliary_device_id *id_table;
|
|
};
|
|
|
|
static inline void *auxiliary_get_drvdata(struct auxiliary_device *auxdev)
|
|
{
|
|
return dev_get_drvdata(&auxdev->dev);
|
|
}
|
|
|
|
static inline void auxiliary_set_drvdata(struct auxiliary_device *auxdev, void *data)
|
|
{
|
|
dev_set_drvdata(&auxdev->dev, data);
|
|
}
|
|
|
|
static inline struct auxiliary_device *to_auxiliary_dev(struct device *dev)
|
|
{
|
|
return container_of(dev, struct auxiliary_device, dev);
|
|
}
|
|
|
|
static inline const struct auxiliary_driver *to_auxiliary_drv(const struct device_driver *drv)
|
|
{
|
|
return container_of(drv, struct auxiliary_driver, driver);
|
|
}
|
|
|
|
int auxiliary_device_init(struct auxiliary_device *auxdev);
|
|
int __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname);
|
|
#define auxiliary_device_add(auxdev) __auxiliary_device_add(auxdev, KBUILD_MODNAME)
|
|
|
|
#ifdef CONFIG_SYSFS
|
|
int auxiliary_device_sysfs_irq_add(struct auxiliary_device *auxdev, int irq);
|
|
void auxiliary_device_sysfs_irq_remove(struct auxiliary_device *auxdev,
|
|
int irq);
|
|
#else /* CONFIG_SYSFS */
|
|
static inline int
|
|
auxiliary_device_sysfs_irq_add(struct auxiliary_device *auxdev, int irq)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void
|
|
auxiliary_device_sysfs_irq_remove(struct auxiliary_device *auxdev, int irq) {}
|
|
#endif
|
|
|
|
static inline void auxiliary_device_uninit(struct auxiliary_device *auxdev)
|
|
{
|
|
mutex_destroy(&auxdev->sysfs.lock);
|
|
put_device(&auxdev->dev);
|
|
}
|
|
|
|
static inline void auxiliary_device_delete(struct auxiliary_device *auxdev)
|
|
{
|
|
device_del(&auxdev->dev);
|
|
}
|
|
|
|
int __auxiliary_driver_register(struct auxiliary_driver *auxdrv, struct module *owner,
|
|
const char *modname);
|
|
#define auxiliary_driver_register(auxdrv) \
|
|
__auxiliary_driver_register(auxdrv, THIS_MODULE, KBUILD_MODNAME)
|
|
|
|
void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv);
|
|
|
|
/**
|
|
* module_auxiliary_driver() - Helper macro for registering an auxiliary driver
|
|
* @__auxiliary_driver: auxiliary driver struct
|
|
*
|
|
* Helper macro for auxiliary drivers which do not do anything special in
|
|
* module init/exit. This eliminates a lot of boilerplate. Each module may only
|
|
* use this macro once, and calling it replaces module_init() and module_exit()
|
|
*
|
|
* .. code-block:: c
|
|
*
|
|
* module_auxiliary_driver(my_drv);
|
|
*/
|
|
#define module_auxiliary_driver(__auxiliary_driver) \
|
|
module_driver(__auxiliary_driver, auxiliary_driver_register, auxiliary_driver_unregister)
|
|
|
|
struct auxiliary_device *auxiliary_find_device(struct device *start,
|
|
const void *data,
|
|
int (*match)(struct device *dev, const void *data));
|
|
|
|
#endif /* _AUXILIARY_BUS_H_ */
|