|
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