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