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