]>
Commit | Line | Data |
---|---|---|
201417d7 SG |
1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
2 | /* | |
3 | * Copyright 2021 Google LLC | |
4 | * Written by Simon Glass <[email protected]> | |
5 | */ | |
6 | ||
7 | #ifndef __bootdev_h | |
8 | #define __bootdev_h | |
9 | ||
10 | #include <linux/list.h> | |
11 | ||
12 | struct bootflow; | |
13 | struct bootflow_iter; | |
bd90b092 | 14 | struct bootstd_priv; |
201417d7 SG |
15 | struct udevice; |
16 | ||
17 | /** | |
18 | * enum bootdev_prio_t - priority of each bootdev | |
19 | * | |
20 | * These values are associated with each bootdev and set up by the driver. | |
21 | * | |
22 | * Smallest value is the highest priority. By default, bootdevs are scanned from | |
23 | * highest to lowest priority | |
eacc2611 SG |
24 | * |
25 | * BOOTDEVP_0_NONE: Invalid value, do not use | |
26 | * @BOOTDEVP_6_PRE_SCAN: Scan bootdevs with this priority always, before | |
27 | * starting any bootflow scan | |
28 | * @BOOTDEVP_2_INTERNAL_FAST: Internal devices which don't need scanning and | |
29 | * generally very quick to access, e.g. less than 100ms | |
30 | * @BOOTDEVP_3_INTERNAL_SLOW: Internal devices which don't need scanning but | |
31 | * take a significant fraction of a second to access | |
32 | * @BOOTDEVP_4_SCAN_FAST: Extenal devices which need scanning or bus | |
33 | * enumeration to find, but this enumeration happens quickly, typically under | |
34 | * 100ms | |
35 | * @BOOTDEVP_5_SCAN_SLOW: Extenal devices which need scanning or bus | |
36 | * enumeration to find. The enumeration takes significant fraction of a second | |
37 | * to complete | |
38 | * @BOOTDEVP_6_NET_BASE: Basic network devices which are quickly and easily | |
39 | * available. Typically used for an internal Ethernet device | |
40 | * @BOOTDEVP_7_NET_FALLBACK: Secondary network devices which require extra time | |
41 | * to start up, or are less desirable. Typically used for secondary Ethernet | |
42 | * devices. Note that USB ethernet devices are found during USB enumeration, | |
43 | * so do not use this priority | |
201417d7 SG |
44 | */ |
45 | enum bootdev_prio_t { | |
eacc2611 SG |
46 | BOOTDEVP_0_NONE, |
47 | BOOTDEVP_1_PRE_SCAN, | |
48 | BOOTDEVP_2_INTERNAL_FAST, | |
49 | BOOTDEVP_3_INTERNAL_SLOW, | |
50 | BOOTDEVP_4_SCAN_FAST, | |
51 | BOOTDEVP_5_SCAN_SLOW, | |
52 | BOOTDEVP_6_NET_BASE, | |
53 | BOOTDEVP_7_NET_FALLBACK, | |
201417d7 SG |
54 | |
55 | BOOTDEVP_COUNT, | |
56 | }; | |
57 | ||
bd90b092 SG |
58 | struct bootdev_hunter; |
59 | ||
60 | /** | |
61 | * bootdev_hunter_func - function to probe for bootdevs of a given type | |
62 | * | |
63 | * This should hunt around for bootdevs of the given type, binding them as it | |
64 | * finds them. This may involve bus enumeration, etc. | |
65 | * | |
66 | * @info: Info structure describing this hunter | |
67 | * @show: true to show information from the hunter | |
68 | * Returns: 0 if OK, -ve on error | |
69 | */ | |
70 | typedef int (*bootdev_hunter_func)(struct bootdev_hunter *info, bool show); | |
71 | ||
72 | /** | |
73 | * struct bootdev_hunter - information about how to hunt for bootdevs | |
74 | * | |
75 | * @prio: Scanning priority of this hunter | |
76 | * @uclass: Uclass ID for the media associated with this bootdev | |
77 | * @drv: bootdev driver for the things found by this hunter | |
78 | * @hunt: Function to call to hunt for bootdevs of this type (NULL if none) | |
79 | * | |
80 | * Some bootdevs are not visible until other devices are enumerated. For | |
81 | * example, USB bootdevs only appear when the USB bus is enumerated. | |
82 | * | |
83 | * On the other hand, we don't always want to enumerate all the buses just to | |
84 | * find the first valid bootdev. Ideally we want to work through them in | |
85 | * priority order, so that the fastest bootdevs are discovered first. | |
86 | * | |
87 | * This struct holds information about the bootdev so we can determine the probe | |
88 | * order and how to hunt for bootdevs of this type | |
89 | */ | |
90 | struct bootdev_hunter { | |
91 | enum bootdev_prio_t prio; | |
92 | enum uclass_id uclass; | |
93 | struct driver *drv; | |
94 | bootdev_hunter_func hunt; | |
95 | }; | |
96 | ||
97 | /* declare a new bootdev hunter */ | |
98 | #define BOOTDEV_HUNTER(__name) \ | |
99 | ll_entry_declare(struct bootdev_hunter, __name, bootdev_hunter) | |
100 | ||
101 | /* access a bootdev hunter by name */ | |
102 | #define BOOTDEV_HUNTER_GET(__name) \ | |
103 | ll_entry_get(struct bootdev_hunter, __name, bootdev_hunter) | |
104 | ||
201417d7 SG |
105 | /** |
106 | * struct bootdev_uc_plat - uclass information about a bootdev | |
107 | * | |
108 | * This is attached to each device in the bootdev uclass and accessible via | |
109 | * dev_get_uclass_plat(dev) | |
110 | * | |
111 | * @bootflows: List of available bootflows for this bootdev | |
112 | * @piro: Priority of this bootdev | |
113 | */ | |
114 | struct bootdev_uc_plat { | |
115 | struct list_head bootflow_head; | |
116 | enum bootdev_prio_t prio; | |
117 | }; | |
118 | ||
119 | /** struct bootdev_ops - Operations for the bootdev uclass */ | |
120 | struct bootdev_ops { | |
121 | /** | |
b85fc8db SG |
122 | * get_bootflow() - get a bootflow (optional) |
123 | * | |
124 | * If this is NULL then the default implementaton is used, which is | |
125 | * default_get_bootflow() | |
201417d7 SG |
126 | * |
127 | * @dev: Bootflow device to check | |
128 | * @iter: Provides current dev, part, method to get. Should update | |
129 | * max_part if there is a partition table. Should update state, | |
130 | * subdir, fname, buf, size according to progress | |
131 | * @bflow: Updated bootflow if found | |
132 | * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this | |
133 | * device, -ENOSYS if this device doesn't support bootflows, | |
134 | * other -ve value on other error | |
135 | */ | |
136 | int (*get_bootflow)(struct udevice *dev, struct bootflow_iter *iter, | |
137 | struct bootflow *bflow); | |
138 | }; | |
139 | ||
140 | #define bootdev_get_ops(dev) ((struct bootdev_ops *)(dev)->driver->ops) | |
141 | ||
142 | /** | |
143 | * bootdev_get_bootflow() - get a bootflow | |
144 | * | |
145 | * @dev: Bootflow device to check | |
146 | * @iter: Provides current part, method to get | |
147 | * @bflow: Returns bootflow if found | |
148 | * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this device, | |
149 | * -ENOSYS if this device doesn't support bootflows, other -ve value on | |
150 | * other error | |
151 | */ | |
152 | int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, | |
153 | struct bootflow *bflow); | |
154 | ||
155 | /** | |
156 | * bootdev_bind() - Bind a new named bootdev device | |
157 | * | |
158 | * @parent: Parent of the new device | |
159 | * @drv_name: Driver name to use for the bootdev device | |
160 | * @name: Name for the device (parent name is prepended) | |
161 | * @devp: the new device (which has not been probed) | |
162 | */ | |
163 | int bootdev_bind(struct udevice *parent, const char *drv_name, const char *name, | |
164 | struct udevice **devp); | |
165 | ||
166 | /** | |
167 | * bootdev_find_in_blk() - Find a bootdev in a block device | |
168 | * | |
169 | * @dev: Bootflow device associated with this block device | |
170 | * @blk: Block device to search | |
171 | * @iter: Provides current dev, part, method to get. Should update | |
172 | * max_part if there is a partition table | |
173 | * @bflow: On entry, provides information about the partition and device to | |
174 | * check. On exit, returns bootflow if found | |
175 | * Return: 0 if found, -ESHUTDOWN if no more bootflows, other -ve on error | |
176 | */ | |
177 | int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, | |
178 | struct bootflow_iter *iter, struct bootflow *bflow); | |
179 | ||
180 | /** | |
181 | * bootdev_list() - List all available bootdevs | |
182 | * | |
183 | * @probe: true to probe devices, false to leave them as is | |
184 | */ | |
185 | void bootdev_list(bool probe); | |
186 | ||
187 | /** | |
188 | * bootdev_clear_bootflows() - Clear bootflows from a bootdev | |
189 | * | |
190 | * Each bootdev maintains a list of discovered bootflows. This provides a | |
191 | * way to clear it. These bootflows are removed from the global list too. | |
192 | * | |
193 | * @dev: bootdev device to update | |
194 | */ | |
195 | void bootdev_clear_bootflows(struct udevice *dev); | |
196 | ||
197 | /** | |
198 | * bootdev_add_bootflow() - Add a bootflow to the bootdev's list | |
199 | * | |
200 | * All fields in @bflow must be set up. Note that @bflow->dev is used to add the | |
201 | * bootflow to that device. | |
202 | * | |
203 | * @dev: Bootdevice device to add to | |
204 | * @bflow: Bootflow to add. Note that fields within bflow must be allocated | |
205 | * since this function takes over ownership of these. This functions makes | |
206 | * a copy of @bflow itself (without allocating its fields again), so the | |
207 | * caller must dispose of the memory used by the @bflow pointer itself | |
208 | * Return: 0 if OK, -ENOMEM if out of memory | |
209 | */ | |
210 | int bootdev_add_bootflow(struct bootflow *bflow); | |
211 | ||
212 | /** | |
213 | * bootdev_first_bootflow() - Get the first bootflow from a bootdev | |
214 | * | |
215 | * Returns the first bootflow attached to a bootdev | |
216 | * | |
217 | * @dev: bootdev device | |
218 | * @bflowp: Returns a pointer to the bootflow | |
219 | * Return: 0 if found, -ENOENT if there are no bootflows | |
220 | */ | |
221 | int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp); | |
222 | ||
223 | /** | |
224 | * bootdev_next_bootflow() - Get the next bootflow from a bootdev | |
225 | * | |
226 | * Returns the next bootflow attached to a bootdev | |
227 | * | |
228 | * @bflowp: On entry, the last bootflow returned , e.g. from | |
229 | * bootdev_first_bootflow() | |
230 | * Return: 0 if found, -ENOENT if there are no more bootflows | |
231 | */ | |
232 | int bootdev_next_bootflow(struct bootflow **bflowp); | |
233 | ||
234 | /** | |
235 | * bootdev_find_by_label() - Look up a bootdev by label | |
236 | * | |
237 | * Each bootdev has a label which contains the media-uclass name and a number, | |
238 | * e.g. 'mmc2'. This looks up the label and returns the associated bootdev | |
239 | * | |
240 | * The lookup is performed based on the media device's sequence number. So for | |
241 | * 'mmc2' this looks for a device in UCLASS_MMC with a dev_seq() of 2. | |
242 | * | |
243 | * @label: Label to look up (e.g. "mmc1" or "mmc0") | |
244 | * @devp: Returns the bootdev device found, or NULL if none (note it does not | |
245 | * return the media device, but its bootdev child) | |
d9f48579 SG |
246 | * @method_flagsp: If non-NULL, returns any flags implied by the label |
247 | * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails | |
201417d7 | 248 | * Return: 0 if OK, -EINVAL if the uclass is not supported by this board, |
d9f48579 | 249 | * -ENOENT if there is no device with that number |
201417d7 | 250 | */ |
d9f48579 SG |
251 | int bootdev_find_by_label(const char *label, struct udevice **devp, |
252 | int *method_flagsp); | |
201417d7 SG |
253 | |
254 | /** | |
255 | * bootdev_find_by_any() - Find a bootdev by name, label or sequence | |
256 | * | |
257 | * @name: name (e.g. "mmc2.bootdev"), label ("mmc2"), or sequence ("2") to find | |
258 | * @devp: returns the device found, on success | |
d9f48579 SG |
259 | * @method_flagsp: If non-NULL, returns any flags implied by the label |
260 | * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails | |
1736b4af | 261 | * Return: 0 if OK, -EPFNOSUPPORT if the uclass is not supported by this board, |
d9f48579 | 262 | * -ENOENT if there is no device with that number |
201417d7 | 263 | */ |
d9f48579 SG |
264 | int bootdev_find_by_any(const char *name, struct udevice **devp, |
265 | int *method_flagsp); | |
201417d7 SG |
266 | |
267 | /** | |
47aedc29 | 268 | * bootdev_setup_iter() - Set up iteration through bootdevs |
201417d7 | 269 | * |
91943ff7 SG |
270 | * This sets up the an interation, based on the provided device or label. If |
271 | * neither is provided, the iteration is based on the priority of each bootdev, | |
272 | * the * bootdev-order property in the bootstd node (or the boot_targets env | |
273 | * var). | |
201417d7 SG |
274 | * |
275 | * @iter: Iterator to update with the order | |
91943ff7 | 276 | * @label: label to scan, or NULL to scan all |
201417d7 SG |
277 | * @devp: On entry, *devp is NULL to scan all, otherwise this is the (single) |
278 | * device to scan. Returns the first device to use, which is the passed-in | |
279 | * @devp if it was non-NULL | |
47aedc29 SG |
280 | * @method_flagsp: If non-NULL, returns any flags implied by the label |
281 | * (enum bootflow_meth_flags_t), 0 if none | |
201417d7 SG |
282 | * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve |
283 | * on other error | |
284 | */ | |
91943ff7 SG |
285 | int bootdev_setup_iter(struct bootflow_iter *iter, const char *label, |
286 | struct udevice **devp, int *method_flagsp); | |
201417d7 | 287 | |
bd90b092 SG |
288 | /** |
289 | * bootdev_list_hunters() - List the available bootdev hunters | |
290 | * | |
291 | * These provide a way to find new bootdevs by enumerating buses, etc. This | |
292 | * function lists the available hunters | |
293 | * | |
294 | * @std: Pointer to bootstd private info | |
295 | */ | |
296 | void bootdev_list_hunters(struct bootstd_priv *std); | |
297 | ||
c7b63d50 SG |
298 | /** |
299 | * bootdev_hunt() - Hunt for bootdevs matching a particular spec | |
300 | * | |
301 | * This runs the selected hunter (or all if @spec is NULL) to try to find new | |
302 | * bootdevs. | |
303 | * | |
304 | * @spec: Spec to match, e.g. "mmc0", or NULL for any. If provided, this must | |
305 | * match a uclass name so that the hunter can be determined. Any trailing number | |
306 | * is ignored | |
307 | * @show: true to show each hunter before using it | |
308 | * Returns: 0 if OK, -ve on error | |
309 | */ | |
310 | int bootdev_hunt(const char *spec, bool show); | |
311 | ||
79a7d4a6 SG |
312 | /** |
313 | * bootdev_hunt_prio() - Hunt for bootdevs of a particular priority | |
314 | * | |
315 | * This runs all hunters which can find bootdevs of the given priority. | |
316 | * | |
317 | * @prio: Priority to use | |
318 | * @show: true to show each hunter as it is used | |
319 | * Returns: 0 if OK, -ve on error | |
320 | */ | |
321 | int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show); | |
322 | ||
66e3dce7 SG |
323 | /** |
324 | * bootdev_hunt_and_find_by_label() - Hunt for bootdevs by label | |
325 | * | |
326 | * Runs the hunter for the label, then tries to find the bootdev, possible | |
327 | * created by the hunter | |
328 | * | |
329 | * @label: Label to look up (e.g. "mmc1" or "mmc0") | |
330 | * @devp: Returns the bootdev device found, or NULL if none (note it does not | |
331 | * return the media device, but its bootdev child) | |
332 | * @method_flagsp: If non-NULL, returns any flags implied by the label | |
333 | * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails | |
334 | * Return: 0 if OK, -EINVAL if the uclass is not supported by this board, | |
335 | * -ENOENT if there is no device with that number | |
336 | */ | |
337 | int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp, | |
338 | int *method_flagsp); | |
339 | ||
e4b69489 SG |
340 | /** |
341 | * bootdev_next_label() - Move to the next bootdev in the label sequence | |
342 | * | |
343 | * Looks through the remaining labels until it finds one that matches a bootdev. | |
344 | * Bootdev scanners are used as needed. For example a label "mmc1" results in | |
345 | * running the "mmc" bootdrv. | |
346 | * | |
347 | * @iter: Interation info, containing iter->cur_label | |
348 | * @devp: New bootdev found, if any was found | |
349 | * @method_flagsp: If non-NULL, returns any flags implied by the label | |
350 | * (enum bootflow_meth_flags_t), 0 if none | |
351 | * Returns 0 if OK, -ENODEV if no bootdev was found | |
352 | */ | |
353 | int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp, | |
354 | int *method_flagsp); | |
355 | ||
43e89a30 SG |
356 | /** |
357 | * bootdev_next_prio() - Find the next bootdev in priority order | |
358 | * | |
359 | * This moves @devp to the next bootdev with the current priority. If there is | |
360 | * none, then it moves to the next priority and scans for new bootdevs there. | |
361 | * | |
362 | * @iter: Interation info, containing iter->cur_prio | |
363 | * @devp: On entry this is the previous bootdev that was considered. On exit | |
364 | * this is the new bootdev, if any was found | |
365 | * Returns 0 on success (*devp is updated), -ENODEV if there are no more | |
366 | * bootdevs at any priority | |
367 | */ | |
368 | int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp); | |
369 | ||
201417d7 SG |
370 | #if CONFIG_IS_ENABLED(BOOTSTD) |
371 | /** | |
3a2cb96e SG |
372 | * bootdev_setup_for_dev() - Bind a new bootdev device (deprecated) |
373 | * | |
374 | * Please use bootdev_setup_sibling_blk() instead since it supports multiple | |
375 | * (child) block devices for each media device. | |
201417d7 SG |
376 | * |
377 | * Creates a bootdev device as a child of @parent. This should be called from | |
378 | * the driver's bind() method or its uclass' post_bind() method. | |
379 | * | |
380 | * If a child bootdev already exists, this function does nothing | |
381 | * | |
382 | * @parent: Parent device (e.g. MMC or Ethernet) | |
383 | * @drv_name: Name of bootdev driver to bind | |
384 | * Return: 0 if OK, -ve on error | |
385 | */ | |
386 | int bootdev_setup_for_dev(struct udevice *parent, const char *drv_name); | |
387 | ||
388 | /** | |
389 | * bootdev_setup_for_blk() - Bind a new bootdev device for a blk device | |
390 | * | |
391 | * Creates a bootdev device as a sibling of @blk. This should be called from | |
392 | * the driver's bind() method or its uclass' post_bind() method, at the same | |
393 | * time as the bould device is bound | |
394 | * | |
395 | * If a device of the same name already exists, this function does nothing | |
396 | * | |
397 | * @parent: Parent device (e.g. MMC or Ethernet) | |
398 | * @drv_name: Name of bootdev driver to bind | |
399 | * Return: 0 if OK, -ve on error | |
400 | */ | |
401 | int bootdev_setup_sibling_blk(struct udevice *blk, const char *drv_name); | |
402 | ||
403 | /** | |
404 | * bootdev_get_sibling_blk() - Locate the block device for a bootdev | |
405 | * | |
406 | * @dev: bootdev to check | |
407 | * @blkp: returns associated block device | |
408 | * Return: 0 if OK, -EINVAL if @dev is not a bootdev device, other -ve on other | |
409 | * error | |
410 | */ | |
411 | int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp); | |
412 | ||
413 | /** | |
414 | * bootdev_unbind_dev() - Unbind a bootdev device | |
415 | * | |
416 | * Remove and unbind a bootdev device which is a child of @parent. This should | |
417 | * be called from the driver's unbind() method or its uclass' post_bind() | |
418 | * method. | |
419 | * | |
420 | * @parent: Parent device (e.g. MMC or Ethernet) | |
421 | * Return: 0 if OK, -ve on error | |
422 | */ | |
423 | int bootdev_unbind_dev(struct udevice *parent); | |
424 | #else | |
425 | static inline int bootdev_setup_for_dev(struct udevice *parent, | |
426 | const char *drv_name) | |
427 | { | |
428 | return 0; | |
429 | } | |
430 | ||
431 | static inline int bootdev_setup_sibling_blk(struct udevice *blk, | |
432 | const char *drv_name) | |
433 | { | |
434 | return 0; | |
435 | } | |
436 | ||
437 | static inline int bootdev_unbind_dev(struct udevice *parent) | |
438 | { | |
439 | return 0; | |
440 | } | |
441 | #endif | |
442 | ||
443 | #endif |