1.. SPDX-License-Identifier: GPL-2.0-only
2
3.. _auxiliary_bus:
4
5=============
6Auxiliary Bus
7=============
8
9In some subsystems, the functionality of the core device (PCI/ACPI/other) is
10too complex for a single device to be managed by a monolithic driver
11(e.g. Sound Open Firmware), multiple devices might implement a common
12intersection of functionality (e.g. NICs + RDMA), or a driver may want to
13export an interface for another subsystem to drive (e.g. SIOV Physical Function
14export Virtual Function management).  A split of the functinoality into child-
15devices representing sub-domains of functionality makes it possible to
16compartmentalize, layer, and distribute domain-specific concerns via a Linux
17device-driver model.
18
19An example for this kind of requirement is the audio subsystem where a single
20IP is handling multiple entities such as HDMI, Soundwire, local devices such as
21mics/speakers etc. The split for the core's functionality can be arbitrary or
22be defined by the DSP firmware topology and include hooks for test/debug. This
23allows for the audio core device to be minimal and focused on hardware-specific
24control and communication.
25
26Each auxiliary_device represents a part of its parent functionality. The
27generic behavior can be extended and specialized as needed by encapsulating an
28auxiliary_device within other domain-specific structures and the use of .ops
29callbacks. Devices on the auxiliary bus do not share any structures and the use
30of a communication channel with the parent is domain-specific.
31
32Note that ops are intended as a way to augment instance behavior within a class
33of auxiliary devices, it is not the mechanism for exporting common
34infrastructure from the parent. Consider EXPORT_SYMBOL_NS() to convey
35infrastructure from the parent module to the auxiliary module(s).
36
37
38When Should the Auxiliary Bus Be Used
39=====================================
40
41The auxiliary bus is to be used when a driver and one or more kernel modules,
42who share a common header file with the driver, need a mechanism to connect and
43provide access to a shared object allocated by the auxiliary_device's
44registering driver.  The registering driver for the auxiliary_device(s) and the
45kernel module(s) registering auxiliary_drivers can be from the same subsystem,
46or from multiple subsystems.
47
48The emphasis here is on a common generic interface that keeps subsystem
49customization out of the bus infrastructure.
50
51One example is a PCI network device that is RDMA-capable and exports a child
52device to be driven by an auxiliary_driver in the RDMA subsystem.  The PCI
53driver allocates and registers an auxiliary_device for each physical
54function on the NIC.  The RDMA driver registers an auxiliary_driver that claims
55each of these auxiliary_devices.  This conveys data/ops published by the parent
56PCI device/driver to the RDMA auxiliary_driver.
57
58Another use case is for the PCI device to be split out into multiple sub
59functions.  For each sub function an auxiliary_device is created.  A PCI sub
60function driver binds to such devices that creates its own one or more class
61devices.  A PCI sub function auxiliary device is likely to be contained in a
62struct with additional attributes such as user defined sub function number and
63optional attributes such as resources and a link to the parent device.  These
64attributes could be used by systemd/udev; and hence should be initialized
65before a driver binds to an auxiliary_device.
66
67A key requirement for utilizing the auxiliary bus is that there is no
68dependency on a physical bus, device, register accesses or regmap support.
69These individual devices split from the core cannot live on the platform bus as
70they are not physical devices that are controlled by DT/ACPI.  The same
71argument applies for not using MFD in this scenario as MFD relies on individual
72function devices being physical devices.
73
74Auxiliary Device
75================
76
77An auxiliary_device represents a part of its parent device's functionality. It
78is given a name that, combined with the registering drivers KBUILD_MODNAME,
79creates a match_name that is used for driver binding, and an id that combined
80with the match_name provide a unique name to register with the bus subsystem.
81
82Registering an auxiliary_device is a two-step process.  First call
83auxiliary_device_init(), which checks several aspects of the auxiliary_device
84struct and performs a device_initialize().  After this step completes, any
85error state must have a call to auxiliary_device_uninit() in its resolution path.
86The second step in registering an auxiliary_device is to perform a call to
87auxiliary_device_add(), which sets the name of the device and add the device to
88the bus.
89
90Unregistering an auxiliary_device is also a two-step process to mirror the
91register process.  First call auxiliary_device_delete(), then call
92auxiliary_device_uninit().
93
94.. code-block:: c
95
96	struct auxiliary_device {
97		struct device dev;
98                const char *name;
99		u32 id;
100	};
101
102If two auxiliary_devices both with a match_name "mod.foo" are registered onto
103the bus, they must have unique id values (e.g. "x" and "y") so that the
104registered devices names are "mod.foo.x" and "mod.foo.y".  If match_name + id
105are not unique, then the device_add fails and generates an error message.
106
107The auxiliary_device.dev.type.release or auxiliary_device.dev.release must be
108populated with a non-NULL pointer to successfully register the auxiliary_device.
109
110The auxiliary_device.dev.parent must also be populated.
111
112Auxiliary Device Memory Model and Lifespan
113------------------------------------------
114
115The registering driver is the entity that allocates memory for the
116auxiliary_device and register it on the auxiliary bus.  It is important to note
117that, as opposed to the platform bus, the registering driver is wholly
118responsible for the management for the memory used for the driver object.
119
120A parent object, defined in the shared header file, contains the
121auxiliary_device.  It also contains a pointer to the shared object(s), which
122also is defined in the shared header.  Both the parent object and the shared
123object(s) are allocated by the registering driver.  This layout allows the
124auxiliary_driver's registering module to perform a container_of() call to go
125from the pointer to the auxiliary_device, that is passed during the call to the
126auxiliary_driver's probe function, up to the parent object, and then have
127access to the shared object(s).
128
129The memory for the auxiliary_device is freed only in its release() callback
130flow as defined by its registering driver.
131
132The memory for the shared object(s) must have a lifespan equal to, or greater
133than, the lifespan of the memory for the auxiliary_device.  The auxiliary_driver
134should only consider that this shared object is valid as long as the
135auxiliary_device is still registered on the auxiliary bus.  It is up to the
136registering driver to manage (e.g. free or keep available) the memory for the
137shared object beyond the life of the auxiliary_device.
138
139The registering driver must unregister all auxiliary devices before its own
140driver.remove() is completed.
141
142Auxiliary Drivers
143=================
144
145Auxiliary drivers follow the standard driver model convention, where
146discovery/enumeration is handled by the core, and drivers
147provide probe() and remove() methods. They support power management
148and shutdown notifications using the standard conventions.
149
150.. code-block:: c
151
152	struct auxiliary_driver {
153		int (*probe)(struct auxiliary_device *,
154                             const struct auxiliary_device_id *id);
155		void (*remove)(struct auxiliary_device *);
156		void (*shutdown)(struct auxiliary_device *);
157		int (*suspend)(struct auxiliary_device *, pm_message_t);
158		int (*resume)(struct auxiliary_device *);
159		struct device_driver driver;
160		const struct auxiliary_device_id *id_table;
161	};
162
163Auxiliary drivers register themselves with the bus by calling
164auxiliary_driver_register(). The id_table contains the match_names of auxiliary
165devices that a driver can bind with.
166
167Example Usage
168=============
169
170Auxiliary devices are created and registered by a subsystem-level core device
171that needs to break up its functionality into smaller fragments. One way to
172extend the scope of an auxiliary_device is to encapsulate it within a domain-
173pecific structure defined by the parent device. This structure contains the
174auxiliary_device and any associated shared data/callbacks needed to establish
175the connection with the parent.
176
177An example is:
178
179.. code-block:: c
180
181        struct foo {
182		struct auxiliary_device auxdev;
183		void (*connect)(struct auxiliary_device *auxdev);
184		void (*disconnect)(struct auxiliary_device *auxdev);
185		void *data;
186        };
187
188The parent device then registers the auxiliary_device by calling
189auxiliary_device_init(), and then auxiliary_device_add(), with the pointer to
190the auxdev member of the above structure. The parent provides a name for the
191auxiliary_device that, combined with the parent's KBUILD_MODNAME, creates a
192match_name that is be used for matching and binding with a driver.
193
194Whenever an auxiliary_driver is registered, based on the match_name, the
195auxiliary_driver's probe() is invoked for the matching devices.  The
196auxiliary_driver can also be encapsulated inside custom drivers that make the
197core device's functionality extensible by adding additional domain-specific ops
198as follows:
199
200.. code-block:: c
201
202	struct my_ops {
203		void (*send)(struct auxiliary_device *auxdev);
204		void (*receive)(struct auxiliary_device *auxdev);
205	};
206
207
208	struct my_driver {
209		struct auxiliary_driver auxiliary_drv;
210		const struct my_ops ops;
211	};
212
213An example of this type of usage is:
214
215.. code-block:: c
216
217	const struct auxiliary_device_id my_auxiliary_id_table[] = {
218		{ .name = "foo_mod.foo_dev" },
219		{ },
220	};
221
222	const struct my_ops my_custom_ops = {
223		.send = my_tx,
224		.receive = my_rx,
225	};
226
227	const struct my_driver my_drv = {
228		.auxiliary_drv = {
229			.name = "myauxiliarydrv",
230			.id_table = my_auxiliary_id_table,
231			.probe = my_probe,
232			.remove = my_remove,
233			.shutdown = my_shutdown,
234		},
235		.ops = my_custom_ops,
236	};
237